如何禁止某些代码调用 System.exit()

如何禁止调用 System.exit()

说明

System.exit() 的本质是通知 JVM 关闭。

一般来说,有两种禁用 System.exit() 的办法:

  • 安全管理器
  • 安全策略

本质都是JRE 提供的本地实现,在执行之前进行权限判断。

因为System.exit() 是一种很暴力的手段,如果在 Client 模式下自己写个小程序无所谓,但是在 Server 上多个程序、或者多线程时就会有很大的麻烦。

示例

使用安全管理器的实现代码如下所示:

1.定义异常类, 继承自 SecurityException

ExitException.java

package com.cncounter.security;

public class ExitException extends SecurityException {
    private static final long serialVersionUID = 1L;
    public final int status;

    public ExitException(int status) {
        super("忽略 Exit方法调用!");
        this.status = status;
    }
}

2.定义安全管理器类, 继承自 SecurityManager

NoExitSecurityManager.java

package com.cncounter.security;

import java.security.Permission;

public class NoExitSecurityManager extends SecurityManager {
    @Override
    public void checkPermission(Permission perm) {
        // allow anything.
    }

    @Override
    public void checkPermission(Permission perm, Object context) {
        // allow anything.
    }

    @Override
    public void checkExit(int status) {
        super.checkExit(status);
        throw new ExitException(status);
    }
}

其中直接拒绝系统退出。

3.增加一个辅助和测试类,实际使用时你也可以自己进行控制。

NoExitHelper.java

package com.cncounter.security;

public class NoExitHelper {

    /**
     * 设置不允许调用 System.exit(status)
     *
     * @throws Exception
     */
    public static void setNoExit() throws Exception {
        System.setSecurityManager(new NoExitSecurityManager());
    }

    public static void main(String[] args) throws Exception {
        setNoExit();
        testNoExit();
        testExit();
        testNoExit();
    }

    public static void testNoExit() throws Exception {
        System.out.println("Printing works");
    }

    public static void testExit() throws Exception {
        try {
            System.exit(42);
        } catch (ExitException e) {
            //
            System.out.println("退出的状态码为: " + e.status);
        }
    }
}

在其中,使用了一个 main 方法来做简单的测试。 控制台输出结果如下:

Printing works
退出的状态码为: 42
Printing works

原问题

原来的问题如下:

I’ve got a few methods that should call System.exit() on certain inputs. Unfortunately, testing these cases causes JUnit to terminate! Putting the method calls in a new Thread doesn’t seem to help, since System.exit() terminates the JVM, not just the current thread. Are there any common patterns for dealing with this? For example, can I subsitute a stub for System.exit()?

大意是:

有一些方法需要测试, 但是在某些特定的输入时就会调用 System.exit()。这就杯具了,这时候 JUnit 测试也跟着退出了! 用一个新线程来调用这种方法也没什么用, 因为 System.exit() 会停止JVM , 而不是退出当前线程。有什么通用的模式来处理这种情况吗? 例如,我能替换掉 System.exit() 方法吗?

建议如下:

Instead of terminating with System.exit(whateverValue), why not throw an unchecked exception? In normal use it will drift all the way out to the JVM’s last-ditch catcher and shut your script down (unless you decide to catch it somewhere along the way, which might be useful someday).

In the JUnit scenario it will be caught by the JUnit framework, which will report that such-and-such test failed and move smoothly along to the next.

翻译如下:

在程序中调用 System.exit(whateverValue) 是一种很不好的编程习惯, 这种情况为什么不抛出一个未检测的异常(unchecked exception)呢? 如果程序中不进行捕获(catch), 抛出的异常会一路漂移到 JVM , 然后就会退出程序(只有主线程的话)。

在 JUnit 的测试场景中异常会被 JUnit 框架捕获, 然后就会报告说某某某测试执行失败,然后就继续下一个单元测试了。

当然,给出的解决方案就是前面的那段代码. 你还可以阅读下面的参考文章,查找其他的解决方案。

参考文章:

日期: 2015年08月25日

人员: 铁锚 http://blog.csdn.net/renfufei

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-30 14:53:38

如何禁止某些代码调用 System.exit()的相关文章

Java: System.exit() 与安全策略

说明 System.exit() 的本质是通知 JVM 关闭. 一般来说.有两种禁用 System.exit() 的办法: 安全管理器 安全策略 本质都是JRE 提供的本地实现,在执行之前进行权限推断. 由于System.exit() 是一种非常暴力的手段.假设在 Client 模式下自己写个小程序无所谓,可是在 Server 上多个程序.或者多线程时就会有非常大的麻烦. 底层源代码 1.先来看看静态方法 System.exit() 的源代码: // System.exit() public s

android开发时,finish()跟System.exit(0)的区别

这两天在弄Android,遇到一个问题:所开发的小游戏中有背景音乐,玩的过程中始终有音乐在放着,然后在我退出游戏后,音乐还在播放! 我看了一下我最开始写的退出游戏的代码,就是简单的finish()语句.我想应该是这个地方出了问题.后来想了想,以前好像见过有用System.exit(0)退出游戏的,然后就尝试了一下,发现问题果然解决了. 现在来彻底弄清楚两者的区别. 首先一个Activity是有生命周期的,onCreate,onStart,onResume,onPause,onStop,onDes

android finish和system.exit(0)的区别

finish是Activity的类,仅仅针对Activity,当调用finish()时,只是将活动推向后台,并没有立即释放内存,活动的资源并没有被清理:当调用System.exit(0)时,杀死了整个进程, 这时候活动所占的资源也会被释放. 在开发android应用时,常常通过按返回键(即keyCode == KeyEvent.KEYCODE_BACK)就能关闭程序,其实大多情况下该应用还在任务里运行着,其实这不是我们想要的结果. 我们可以这样做,当用户点击自定义的退出按钮或返回键时(需要捕获动

android Process.killProcess 和 System.exit(0) 区别

1 Process.killProcess  和 System.exit(0) 两个都会 kill 掉当前进程. 你可以打开 DDMM 查看进程号,进程确实被 kill 掉了. 2 如果是在第一个 Activity 调用 Process.killProcess 或 System.exit(0) 都会 kill 掉当前进程. 但是如果不是在第一个 Activity 中调用,如 ActivityA 启动 ActivityB ,你在 ActivityB 中调用 Process.killProcess

System.exit(-1)和return 的区别

对于只有一个单一方法的类或者系统来说是一样的,但是对于含有多个类和方法,且调用关系比较复杂时就不一样了. System.exit(-1)是指所有程序(方法,类等)停止,系统停止运行. return只是这一个方法停止,并不影响其他方法的顺序运行.比如: void a(){ b(); c(); d(); }其中b()中是return.c()是System.exit(-1);那么 b()会执行,c()会执行,而d()不会被执行. System.exit(int status) public stati

System.exit和Runtime halt区别

看到RM在处理异常的时候使用了两种退出方式,而且是针对不同的异常.特意查询了一些资料来看看,两种方式有什么不同. System.exit 终止当前正在运行的Java虚拟机.参数作为状态代码,按照惯例,一个非零状态码表示异常终止. 用线程描述,在多线程情况下,可能更准确一些 1.调用方法后,线程会退出 2.未捕获的异常被线程抛出,但如果有其他非守护线程,程序将继续运行. 3.反馈状态码,一般在脚本中有用. 4.线程退出,还是做一些清理动作 -----------------------------

System.exit()源码分析

最近代码中常用的System.exit(),就来看看源码. 首先位于java.lang.System中,源码如下: /** * Terminates the currently running Java Virtual Machine. The * argument serves as a status code; by convention, a nonzero status * code indicates abnormal termination. 用来终止当前正在运行的JVM.参数用作状

存储过程--分页与C#代码调用

存储过程: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author:<Author,,QiangWang> -- Create date: <Create Date,,> -- Description:<Description,分页,> -- ===================================

dzx2.5 template\default\forum\viewthread_node.htm代码调用解放(和我一样的菜鳥版)

<!--{block authorverifys}--> <!--{if $_G['setting']['verify']['enabled']}--> <!--{loop $_G['setting']['verify'] $vid $verify}--> <!--{if $verify['available'] && $verify['showicon']}--> <a href="home.php?mod=spacecp&