我正在使用一个第三方库,当它遇到异常时会执行System.exit()
。我正在使用来自jar包的API。有没有办法阻止System.exit()
调用,因为它会导致我的应用关闭?由于许多其他许可问题,我无法在删除System.exit()
后反编译和重新编译jar文件。我曾经在stackoverflow上看到过一个答案(对于我不记得的其他问题),可以使用Java中的SecurityManager
来做这样的事情。
我正在使用一个第三方库,当它遇到异常时会执行System.exit()
。我正在使用来自jar包的API。有没有办法阻止System.exit()
调用,因为它会导致我的应用关闭?由于许多其他许可问题,我无法在删除System.exit()
后反编译和重新编译jar文件。我曾经在stackoverflow上看到过一个答案(对于我不记得的其他问题),可以使用Java中的SecurityManager
来做这样的事情。
您可以安装一个安全管理器来禁用System.exit()
:
private static class ExitTrappedException extends SecurityException { }
private static void forbidSystemExitCall() {
final SecurityManager securityManager = new SecurityManager() {
public void checkPermission( Permission permission ) {
if( "exitVM".equals( permission.getName() ) ) {
throw new ExitTrappedException() ;
}
}
} ;
System.setSecurityManager( securityManager ) ;
}
private static void enableSystemExitCall() {
System.setSecurityManager( null ) ;
}
编辑:Max在下面的评论中指出,从Java 6开始,权限名称实际上是“exitVM. ”+状态,例如“exitVM.0”。
然而,权限
exitVM.*
涵盖所有退出状态,而exitVM
仍然保留为exitVM.*
的简写形式,因此上述代码仍然有效(请参见RuntimePermission
的文档)。
System.exit()
,它将触发一个 SecurityException
...因此您的代码必须处理此情况。 - Stephen CSystem.setSecurityManager(null);
对我来说似乎是一种非常hack的方法。开发者刚刚打开了JRE,使得任何代码都可以做任何事情。虽然我概述的扩展的 SecurityManager
也只是一个玩具版本,但至少它有潜力对第三方API提供更进一步的控制。此外,这种方法似乎可能会对启动自己线程的第三方API失败。 - Andrew ThompsonSecurityManager
来防止System.exit(n)
。import java.awt.*;
import java.awt.event.*;
import java.security.Permission;
/** NoExit demonstrates how to prevent 'child'
applications from ending the VM with a call
to System.exit(0).
@author Andrew Thompson */
public class NoExit extends Frame implements ActionListener {
Button frameLaunch = new Button("Frame"),
exitLaunch = new Button("Exit");
/** Stores a reference to the original security manager. */
ExitManager sm;
public NoExit() {
super("Launcher Application");
sm = new ExitManager( System.getSecurityManager() );
System.setSecurityManager(sm);
setLayout(new GridLayout(0,1));
frameLaunch.addActionListener(this);
exitLaunch.addActionListener(this);
add( frameLaunch );
add( exitLaunch );
pack();
setSize( getPreferredSize() );
}
public void actionPerformed(ActionEvent ae) {
if ( ae.getSource()==frameLaunch ) {
TargetFrame tf = new TargetFrame();
} else {
// change back to the standard SM that allows exit.
System.setSecurityManager(
sm.getOriginalSecurityManager() );
// exit the VM when *we* want
System.exit(0);
}
}
public static void main(String[] args) {
NoExit ne = new NoExit();
ne.setVisible(true);
}
}
/** This example frame attempts to System.exit(0)
on closing, we must prevent it from doing so. */
class TargetFrame extends Frame {
static int x=0, y=0;
TargetFrame() {
super("Close Me!");
add(new Label("Hi!"));
addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.out.println("Bye!");
System.exit(0);
}
});
pack();
setSize( getPreferredSize() );
setLocation(++x*10,++y*10);
setVisible(true);
}
}
/** Our custom ExitManager does not allow the VM
to exit, but does allow itself to be replaced by
the original security manager.
@author Andrew Thompson */
class ExitManager extends SecurityManager {
SecurityManager original;
ExitManager(SecurityManager original) {
this.original = original;
}
/** Deny permission to exit the VM. */
public void checkExit(int status) {
throw( new SecurityException() );
}
/** Allow this security manager to be replaced,
if fact, allow pretty much everything. */
public void checkPermission(Permission perm) {
}
public SecurityManager getOriginalSecurityManager() {
return original;
}
}
checkPermission
是否应该委托 original
来执行,以防止 TargetFrame
获得比其他代码更多的特权? - Mike Samuel之前的代码示例部分正确,但我发现它会阻塞我代码对文件的访问。为了解决这个问题,我稍微改写了我的 SecurityManager:
public class MySecurityManager extends SecurityManager {
private SecurityManager baseSecurityManager;
public MySecurityManager(SecurityManager baseSecurityManager) {
this.baseSecurityManager = baseSecurityManager;
}
@Override
public void checkPermission(Permission permission) {
if (permission.getName().startsWith("exitVM")) {
throw new SecurityException("System exit not allowed");
}
if (baseSecurityManager != null) {
baseSecurityManager.checkPermission(permission);
} else {
return;
}
}
}
System.exit()
的第三方库是有问题的。如果他们不修复这个问题,我会考虑寻找更高质量的替代品。 - Stephen C