Java类加载器独立于jar文件的系统类加载器

时间:2014-11-07 09:33:06

标签: java jar jvm classloader urlclassloader

我试图在程序中加载一个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与系统类加载器分离。对此有任何帮助表示赞赏!

3 个答案:

答案 0 :(得分:0)

无论Class Loader如何,

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

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

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