【问题标题】:Java class loader independent from the system class loader for jar filesJava 类加载器独立于 jar 文件的系统类加载器
【发布时间】:2015-01-04 01:27:56
【问题描述】:

我正在尝试在程序中加载一个 jar 文件来调用不同的方法。我有一个可以完成工作的类,但是该类使用URLClassLoader 加载jar 文件,这取决于系统类加载器,因此,例如,如果加载的jar 执行System.exit(),它会完成执行整个应用程序,终止当前运行的 Java 虚拟机。我的意图是,如果加载的 jar 最后执行此操作,它只会完成 jar,而不是整个应用程序。另外,我希望能够关闭 jar,以便稍后在需要时重新启动它。我正在使用以下代码从 jar 中实例化所需的类并从我的应用程序中调用方法:

// Load a class with classloader = new URLClassLoader(libs);
if(loadclass == null)
    loadclass = Class.forName(classname, true, classloader);
// Execute method
if(met == null)
{
    Constructor constructor;
    if(params != null && params.length > 0)
    {
        constructor = loadclass.getConstructor(new Class[]{Object[].class});
        classinstance = constructor.newInstance(new Object[]{params});
    }
    else
    {
        constructor = loadclass.getConstructor(null);
        classinstance = constructor.newInstance(null);
    }
    return (Object)Boolean.TRUE;
}

// Generic instance
if(classinstance == null)
    classinstance = loadclass.newInstance();

// Method invocation
Method method;
if(params != null)
{
    if(params.length > 1)
        method = loadclass.getMethod(met, new Class[]{Object[].class});
    else
        method = loadclass.getMethod(met, new Class[]{Object.class});
}
else
    method = loadclass.getMethod(met);

method.setAccessible(true);
Object ret;
if(params != null)
{
    if(params.length > 1)
        ret = (Object)method.invoke(classinstance, new Object[]{params});
    else
        ret = (Object)method.invoke(classinstance, params[0]);
}
else
    ret = (Object)method.invoke(classinstance, null);

return ret;

我不知道如何将我的URLClassLoader 与系统类加载器分离。对此的任何帮助表示赞赏!

【问题讨论】:

  • System.exit 不是与类加载器相关的东西。你可能对这种方法不走运。也许看看 SecurityManager 这样你就可以阻止退出尝试?
  • 是的。正确的方法是使用SecurityManager。谢谢!

标签: java jar jvm classloader urlclassloader


【解决方案1】:

System.exit() 将退出进程而不管类加载器。放弃系统类加载器可以通过不链接类加载器来完成,但是要注意。这意味着所有系统类都需要重新加载,并且它们不能很好地协同工作。例如,将一个类加载器创建的字符串与来自不同类加载器的包含相同字符的另一个字符串进行比较会失败。

为了防止对 System.exit() 的调用成功,可以将安全管理器配置为错误。

这是System.exit()的代码

public void exit(int status) {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkExit(status);
    }
    Shutdown.exit(status);
}

它在安全管理器上调用security.checkExit。这又是这样实现的:

public void checkExit(int status) {
    checkPermission(new RuntimePermission("exitVM."+status));
}

注意exitVM.<number> 权限的使用。有关安全管理器的更多详细信息,以及安装一个可以阅读here

【讨论】:

  • 谢谢,这对我很有帮助。目前我正在学习如何使用安全管理器来实现一个适合我需要的修改版本。
【解决方案2】:

对 System.exit() 的调用可以被 Java 代理拦截。以下article 讨论了使用 Java 代理在加载时重写字节码以插入日志记录语句。可以使用相同的方法来删除对 System.exit 的调用。

【讨论】:

    【解决方案3】:

    回答System.exit()的问题,方法是使用SecurityManager。

    在使用URLClassLoader丢弃加载的jar文件的情况下,我发现有一些相关的bug: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6630027

    http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6896088

    【讨论】:

      猜你喜欢
      • 2012-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-30
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多