从另一个jar文件访问资源

9 浏览
0 Comments

从另一个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文件内部加载?

0
0 Comments

现在,您可以使用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在编译之后但在启动之前移动到正确的位置)。这个想法是数据可以频繁更新而无需重新编译。但是也很好知道,编译时捆绑资源的相关用例有可能有一个解决方案。

0
0 Comments

解决方法:使用一个类路径通配符或者使用URLClassLoader来访问另一个jar文件中的资源。

解决方法1:使用类路径通配符。

jsvc -cp globalclasspath/*:daemons/service.jar (...)

参考链接:How to use a wildcard in the classpath to add multiple jars?

解决方法2:使用URLClassLoader来读取不在类路径上的JAR文件中的数据。具体步骤如下:

  1. 找到globalclasspath目录中的JAR文件列表。
  2. 从JAR文件列表创建一个URLClassLoader实例。
  3. 从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

0
0 Comments

问题的原因是作者之前使用了错误的方法(getResource)来访问来自另一个jar文件的资源。解决方法是改用getResourceAsStream方法来实现。

以下是整理的

在Java中,如果我们想要从另一个jar文件中访问资源,我们应该使用getResourceAsStream方法。这个方法可以帮助我们从jar文件中获取输入流,以便读取其中的资源。

曾经有人在Stack Overflow上提出了一个类似的问题,他询问如何在Java中从jar文件中读取文件。有人建议他使用getResourceAsStream方法。该方法可以从类路径中获取资源,并返回一个输入流,以便读取其中的内容。

然而,原作者回答说他之前使用了错误的方法getResource,因为他对getResourceAsStream方法不太了解,而且getResource方法似乎更简单。但实际上,getResource方法返回的是一个URL对象,而getResourceAsStream方法返回的是一个输入流。

因此,要正确地从另一个jar文件中访问资源,我们应该使用getResourceAsStream方法,这样我们就可以获取到一个输入流,然后通过输入流读取资源的内容。

希望这篇文章能帮助你解决从另一个jar文件中访问资源的问题。记得使用getResourceAsStream方法来获取输入流,并读取其中的内容。祝你好运!

0