我正在开发一个具有自动更新功能的软件,即使用户对安装文件夹没有写入权限也能正常工作。 为此,应用程序分析类路径并检查单独的用户目录中类路径中的条目是否有更新的JAR文件。在这种情况下,应用程序会生成一个修订的类路径,并启动具有该类路径的新VM。
当java默认类加载器通过插入清单文件中提到的库来更改JAR文件的顺序时,我的问题就出现了。
我将给你一个简化的例子,它缺少很多细节,对真正的更新场景没有意义,但它会解释我的问题。所以我们假设我不允许更改main.jar的内容。
我用
启动应用程序java -jar main.jar
main.jar有一个正确的MANIFEST文件,其中包含Main-Class和Class-Path,引用其他库c.jar和d.jar。
因此,运行时期间的完整Class-Path将是:
main.jar, c.jar, d.jar
顺序很重要,因为main.jar会覆盖c.jar中的类。 现在应用程序发现有可用的更新,这需要额外的库a.jar和b.jar。
因此应用程序现在计算新的类路径:
main.jar, a.jar, b.jar, c.jar, d.jar
同样,顺序很重要,因为a.jar会覆盖d.jar中的类。 现在,应用程序启动一个具有显式类路径的新VM:
java -cp main.jar:a.jar:b.jar:c.jar:d.jar <Main-Class>
不幸的是,java通过在main.jar的位置插入由MANIFEST of main.jar引用的库来改变类路径。所以有效的类路径是:
main.jar, c.jar, d.jar, a.jar, b.jar, c.jar, d.jar
-------- ------------ --------------------------
CP MANIFEST CP
根据该订单,c.jar现在的优先级高于a.jar。而且a.jar中的重写类不会被加载。
这个问题的明显解决方案是提供一个没有清单的main.jar。 但这会导致其他问题,我想避免。
我的问题是:有没有办法在搜索类路径时禁用java的行为以包含来自MANIFEST的引用JAR文件?
答案 0 :(得分:0)
只是一个快速且未经考验的想法。如果您能够在运行时动态加载更新的jar,而不是在命令行中指定它们,则可以为这些jar创建URLClassLoader
并使用该自定义类加载器显式加载类:
URL[] jarurls = new URL[]{jar1,jar2,...};
URLClassLoader customCL= new URLClassLoader (jarurls, getClass().getClassLoader());
Class clazz = Class.forName ("com.blablabla.MyClass1", true, customCL);
MyClass1 instance = (MyClass1)clazz.newInstance();
您可以将驻留在用户文件夹中的每个jar加载到该类加载器中。在实例化类时,您将优先考虑自定义类加载器并在默认类上进行故障转移。
这肯定会给您的设计增加复杂性/风险,因为类现在需要通过反射来实例化。