【问题标题】:Access resources from another jar file从另一个 jar 文件访问资源
【发布时间】:2013-12-07 15:48:35
【问题描述】:

我有一个简单的结构:一个包含一批数据的数据 jar 文件和一个使用数据运行服务的服务 jar 文件。为了方便替换数据,我把它们分开了,service.jar的classpath包含了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 中加载资源吗?

【问题讨论】:

    标签: java classpath jsvc


    【解决方案1】:

    您是否按照此处的建议尝试过getResourceAsStream

    how-to-a-read-file-from-jar-in-java

    【讨论】:

    • 对不起,我实际上已经在使用getResourceAsStream(我写了getResource,因为我不知道有什么区别,而且看起来更简单)
    【解决方案2】:

    解决方案 1

    使用类路径通配符。

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

    见“How to use a wildcard in the classpath to add multiple jars?

    解决方案 2

    要读取不在类路径上的 JAR 中的数据,请使用 URLClassLoader。一般算法是这样的:

    1. globalclasspath 目录中查找 JAR 列表。
    2. 从此 JAR 列表中创建一个 URLClassLoader
    3. URLClassLoader 实例中查找您想要的资源。

    为了在类路径中查找 JAR,我使用了 StackOverflow 文章“Get a list of resources from classpath directory”中的ResourceList

    public class MyClass {
        /**
         * Creates a {@code URLClassLoader} from JAR files found in the
         * globalclasspath directory, assuming that globalclasspath is in
         * {@code 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);
                // Ensure that the JAR exists
                // and is in the globalclasspath directory.
                if (file.isFile() && "globalclasspath".equals(file.getParentFile().getName())) {
                    try {
                        urls.add(file.toURI().toURL());
                    } catch (MalformedURLException e) {
                        // This should never happen.
                        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
    

    【讨论】:

      【解决方案3】:

      您现在可以使用maven-resources-plugin 在您的 jar 之间共享资源!

      在源模块/jar的pom.xml文件中,添加如下插件:

      <artifactId>DATA_MODULE_NAME</artifactId>
      <build>
          <plugins>
              <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-resources-plugin</artifactId>
              </plugin>
          </plugins>
      </build>
      

      这将告诉 maven 将资源文件夹的内容与 jar 一起复制。

      在要访问这些资源的模块中,将其添加到 pom 中的依赖项中:

      <dependencies>
          <dependency>
              <groupId>${project.groupId}</groupId>
              <artifactId>DATA_MODULE_NAME</artifactId>
              <version>${project.version}</version>
          </dependency>
      </dependencies>
      

      当您构建最终 jar 时,源模块中的资源将被复制并使用 getResource() 提供

      【讨论】:

      • 我认为这里的原始要求(虽然很久以前!)是能够从 单独的 jar 文件中加载数据;不是编译的一部分(例如,一个 jar 中的程序,并且数据 jar 在编译后但在启动前移动到正确的位置)。这个想法是数据可以经常更新而无需重新编译。但也很高兴知道在编译时捆绑资源的相关用例有一个可能的解决方案。
      猜你喜欢
      • 2010-11-16
      • 1970-01-01
      • 2012-04-26
      • 1970-01-01
      • 2016-12-29
      • 2012-05-11
      • 1970-01-01
      • 2013-11-20
      相关资源
      最近更新 更多