如何禁止调用 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
版权声明:本文为博主原创文章,未经博主允许不得转载。