从另一个jar文件访问资源
从另一个jar文件访问资源
我有一个简单的结构:一个包含一批数据的数据jar文件,和一个使用这些数据运行服务的服务jar文件。为了方便替换数据,我将它们分开,并且service.jar的类路径包含了data.jar所在的文件夹。
在service.jar中,我使用getResource来加载数据文件。如果数据文件直接位于文件夹中,这个方法可以正常工作,但当它们位于data.jar内部时,就会失败。
这个方法会失败:
all + globalclasspath | + data.jar | + mine.properties + daemons + service.jar jsvc -cp globalclasspath:daemons/service.jar (...) MyClass.class.getClassLoader( ).getResource( "mine.properties" ); // <-- null
但这个方法会成功:
all + globalclasspath | + mine.properties + daemons + service.jar jsvc -cp globalclasspath:daemons/service.jar (...) MyClass.class.getClassLoader( ).getResource( "mine.properties" ); // <-- not null
我不想改变类路径(除非我可以将其更改为与数据jar文件的名称无关的通用路径),但我可以更改getResource的字符串(我尝试过 /data/mine.properties 和 /data.jar/mine.properties,但都无效)。有没有办法可以使资源可以从jar文件内部加载?
现在,您可以使用maven-resources-plugin在jar之间共享资源!在源模块/ jar的pom.xml文件中,添加以下插件:
DATA_MODULE_NAME org.apache.maven.plugins maven-resources-plugin
这将告诉maven将资源文件夹的内容与jar一起复制。
在要访问这些资源的模块中,在pom的依赖项中添加以下内容:
${project.groupId} DATA_MODULE_NAME ${project.version}
当构建最终的jar文件时,源模块中的资源将被复制并可以通过getResource()方法进行访问。
我认为最初的需求(尽管是很久以前的需求!)是能够从一个单独的jar文件中加载数据;这不是编译的一部分(例如,程序在一个jar中,数据jar在编译之后但在启动之前移动到正确的位置)。这个想法是数据可以频繁更新而无需重新编译。但是也很好知道,编译时捆绑资源的相关用例有可能有一个解决方案。
解决方法:使用一个类路径通配符或者使用URLClassLoader来访问另一个jar文件中的资源。
解决方法1:使用类路径通配符。
jsvc -cp globalclasspath/*:daemons/service.jar (...)
参考链接:How to use a wildcard in the classpath to add multiple jars?
解决方法2:使用URLClassLoader来读取不在类路径上的JAR文件中的数据。具体步骤如下:
- 找到globalclasspath目录中的JAR文件列表。
- 从JAR文件列表创建一个URLClassLoader实例。
- 从URLClassLoader实例中查找所需的资源。
为了找到类路径上的JAR文件,我使用了来自StackOverflow文章ResourceList
的方法。
以下是示例代码:
public class MyClass { /** * 从globalclasspath目录中的JAR文件创建{ URLClassLoader}实例, * 假设globalclasspath在{ System.getProperty("java.class.path")}中。 */ private static URLClassLoader createURLClassLoader() { Collection<String> resources = ResourceList.getResources(Pattern.compile(".*\\.jar")); Collection<URL> urls = new ArrayList<URL>(); for (String resource : resources) { File file = new File(resource); // 确保JAR文件存在且在globalclasspath目录中。 if (file.isFile() && "globalclasspath".equals(file.getParentFile().getName())) { try { urls.add(file.toURI().toURL()); } catch (MalformedURLException e) { // 这应该不会发生。 e.printStackTrace(); } } } return new URLClassLoader(urls.toArray(new URL[urls.size()])); } public static void main(String[] args) { URLClassLoader classLoader = createURLClassLoader(); System.out.println(classLoader.getResource("mine.properties")); } }
我运行了以下命令:
java -cp globalclasspath:daemons/service.jar MyClass
终端输出:
jar:file:/workspace/all/globalclasspath/data.jar!/mine.properties
问题的原因是作者之前使用了错误的方法(getResource
)来访问来自另一个jar文件的资源。解决方法是改用getResourceAsStream
方法来实现。
以下是整理的
在Java中,如果我们想要从另一个jar文件中访问资源,我们应该使用getResourceAsStream
方法。这个方法可以帮助我们从jar文件中获取输入流,以便读取其中的资源。
曾经有人在Stack Overflow上提出了一个类似的问题,他询问如何在Java中从jar文件中读取文件。有人建议他使用getResourceAsStream
方法。该方法可以从类路径中获取资源,并返回一个输入流,以便读取其中的内容。
然而,原作者回答说他之前使用了错误的方法getResource
,因为他对getResourceAsStream
方法不太了解,而且getResource
方法似乎更简单。但实际上,getResource
方法返回的是一个URL对象,而getResourceAsStream
方法返回的是一个输入流。
因此,要正确地从另一个jar文件中访问资源,我们应该使用getResourceAsStream
方法,这样我们就可以获取到一个输入流,然后通过输入流读取资源的内容。
希望这篇文章能帮助你解决从另一个jar文件中访问资源的问题。记得使用getResourceAsStream
方法来获取输入流,并读取其中的内容。祝你好运!