编辑:这是项目设置:
IDE:Eclipse:
项目1:"服务器"
src:
com/mainpackage/main.java
libs:
commons-x-0.jar
PluginInterface.jar
libs文件夹中的所有jar都在构建路径上。
项目2:"插件接口"
src:
com/interfaces/plugininterface
项目3:"插件"
src:
com/package/class1.java - (this implements plugininterface)
libs:
library1.jar
PluginInterface.jar
libs文件夹中的所有jar都在构建路径上
所以当我导出插件(Project3)时,我会得到一个这样的jar(从导出中排除了PluginInterface.jar)
com/
com/package/
com/package/class1.class
com/package/class1.java
libs/
libs/library1.jar
library1.jar看起来如下-它不是我写的:
com/
com/stuff/
com/stuff/libclass.java
com/stuff/libclass.class
现在我想在接口上使用"服务器"中的class1:
ClassLoader loader=URLClassLoader.newInstance(
new URL[]{new URL("file:path/to/plugin.jar")},
ClassLoader.getSystemClassLoader()
);
Class<?> pluginclass = Class.forName("com.package.class1", true, loader);
plugininterface ref = (plugininterface)pluginclass.newInstance();
我现在可以使用两个项目都知道的接口从class1调用方法,因为这两个项目的构建路径中都包含"PluginInterface.jar"。
问题:
"服务器"无法识别"libclass",因为它既不在其路径中,也没有从嵌套library1的plugin.jar加载该类。
如果在服务器上无法导入为库,我如何访问此类?
谢谢你的帮助!
编辑:如果有人再次出现这种问题,我会添加ANT文件的构建目标,使其发挥作用:
<target name="build">
<javac destdir="bin" includeantruntime="false" source="1.7" target="1.7">
<src path="src"/>
<classpath refid="Plugin.classpath"/>
</javac>
<unzip src="${libs}/library1.jar" dest="bin/">
<patternset>
<include name="**/*.class"/>
</patternset>
</unzip>
<jar destfile="plugin.jar" basedir="bin"></jar>
</target>
只需将Library jar的内容复制到构建目录中(在我的例子中是./bin/)。然后甚至不需要将库类馈送到Classloader,它在加载Classes时会找到它们。
标准类加载器不支持嵌套的jar文件。您可以通过编程方式提取jar,或者编写自己的类加载器,根据需要解压缩嵌套文件。然而,你会逆流而行:这样的包装是不推荐的。相反,建议将嵌套的jar分解为其父jar。例如,这就是Maven依赖插件所做的,也是使用Leiningen发布Clojure应用程序的默认方式。
为了实现Eclipse的目标,最好的方法似乎是:
-
让Eclipse的ExportJAR向导保存它内部生成的ant构建脚本来构建JAR;
-
调整生成的脚本以满足您的特定需求;
-
以后不再运行向导,而是运行ant脚本。
正如Marko所提到的,您的标准类加载器不会扫描嵌套的jar和其中的嵌套jar。然而,如果你愿意玩TrueZip,你可以很容易地做到这一点,而不必提取档案或任何东西。更好的是,您可以在嵌套的归档中拥有任意深度的嵌套归档。所以你的路径可能看起来像:
/path/to/foo.jar/bar/foo/my.zip/containing/some.tar/com/foo/My.class
如果你觉得用TrueZip编写自己的类加载器很舒服,这将是一个很好的方法。如果不是,那么你必须编写一个实用程序类,先解析路径并提取档案,然后再将其输入标准URLClassloader
。