【问题标题】:Use a dependency's resources?使用依赖项的资源?
【发布时间】:2011-07-14 14:50:51
【问题描述】:

在我的 Maven 项目中,有一个模块(核心)为其类提供了一些资源。在模块内运行类时,它能够获取自己的资源。一切正常。

当依赖于核心的另一个模块尝试运行该类时,东西会中断。 Java 在其中寻找资源的文件夹是这个模块,而不是核心模块。所以课程失败了。

简而言之:如何访问依赖项的资源?


我已经尝试通过在 Core 的 JAR 清单中声明 Class-Path: . 来尝试做到这一点。但是,当列出JSHookLoader.class.getClassLoader().getResources(""); 可用的资源时(如果有任何意义,JSHookLoader 在核心中),我得到:

Resource: W:\programming\quackbot-hg\impl\target\classes
File rebel.xml

Resource: W:\programming\maven-repo\org\quackbot\core\3.5-SNAPSHOT
File core-3.5-SNAPSHOT.jar
File core-3.5-SNAPSHOT.pom
File maven-metadata-local.xml
File _maven.repositories

这当然会使事情复杂化,因为我希望 JAR 本身位于类路径中,而不是 JAR 所在的目录

有什么建议吗?


回到这个项目我仍然有这个问题。其他指南已经讨论过使用 maven-assembly-plugin 和远程资源插件,但这很痛苦,因为所有模块都必须包含怪物插件 XML。

我为什么不将问题简化为:如何将依赖项 JAR 添加到资源列表?

  1. core.jar 在文件夹/resources 下有一些资源。运行 core.jar 我可以在资源列表中看到 /resources。
  2. impl.jar 依赖于 core.jar。虽然 /resources 不在资源列表中,但在运行时会造成严重破坏。

这应该很简单,但我该怎么做呢?我花了几个小时试图找出一个简单干净的方法来做到这一点,但无济于事。

【问题讨论】:

    标签: java maven


    【解决方案1】:

    经过大量搜索,我终于偶然发现了一个解决方案。

    我的解决方案采用核心模块并使用 Maven 依赖插件解压缩它,确保排除 META-INF 文件夹和编译类所在的 org 文件夹。我排除我不想要的东西而不是明确说明我想要的东西的原因是可以轻松添加新资源,而不必一直更新我的 POM。

    我不使用程序集插件或远程资源插件的原因是因为它们使用专用资源模块。我不认为我应该制作一个核心模块和一个核心资源模块,核心资源模块只包含 logback 和 hibernate 配置文件+其他一些东西。

    这是我用来执行此操作的副本

        <build>
            <plugins>
                <!--Extract core's resources-->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <version>2.2</version>
                    <executions>
                        <execution>
                            <id>unpack</id>
                            <phase>generate-resources</phase>
                            <goals>
                                <goal>unpack-dependencies</goal>
                            </goals>
                            <configuration>
                                <includeGroupIds>${project.groupId}</includeGroupIds>
                                <includeArtifactIds>core</includeArtifactIds>
                                <excludeTransitive>true</excludeTransitive>
                                <overWrite>true</overWrite>
                                <outputDirectory>${project.build.directory}/core-resources</outputDirectory>
                                <excludes>org/**,META-INF/**,rebel.xml</excludes>
                                <overWriteReleases>true</overWriteReleases>
                                <overWriteSnapshots>true</overWriteSnapshots>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
            <!--New resource locations-->
            <resources>
                <resource>
                    <filtering>false</filtering>
                    <directory>${project.build.directory}/core-resources</directory>
                </resource>
                <resource>
                    <filtering>false</filtering>
                    <directory>${basedir}/src/main/resources</directory>
                </resource>
            </resources>
        </build> 
    

    【讨论】:

    • 非常感谢您发布您的解决方案!我遇到了这个确切的问题并找到了答案......但它是用 maven 术语编写的,我正在努力破译它。
    • 使用这个时要注意循环依赖。您可能难以发布。
    • 好方法,&lt;overWrite&gt;true&lt;/overWrite&gt;这个属性现在好像不能用了。只是远程它。
    • 完美解决方案。阶段:生成资源很重要。如果我们指定任何其他阶段,例如“package”,那么解压后的资源将不会包含在 fat jar 中。
    • &lt;outputDirectory&gt;${project.build.outputDirectory}&lt;/outputDirectory&gt; 在某些情况下可能是必要的。
    【解决方案2】:

    如果资源位于/src/main/resources 并且 JAR 中的类使用getResourceAsStream() 访问它们,您应该也可以从其他JAR 中的类访问这些文件(也可以使用getResourceAsStream())。这是因为位于/src/main/resources 中的所有文件最终都位于同一个逻辑目录(CLASSPATH)中。换句话说:位于/src/main/resources 中的所有文件以及从/src/main/java 编译的所有类都可以说合并 到一个命名空间中。

    如果即使所有类都使用统一的getResourceAsStream() API,您仍然无法访问文件,则可能存在一些类加载可见性问题。

    【讨论】:

    • 查看我的问题中的更新,它不像你说的那样工作。
    • 看起来这不是 OP 的情况,但通常不要为资源使用相同的文件夹名称。例如。当项目A 拥有资源myfolder/a.txt 并且项目B 拥有myfolder/b.txt,并且B 是A 的依赖项,那么A 将看不到myfolder/b.txt
    【解决方案3】:

    如果您的依赖 JAR 有一个名为 OneDependent 的类,那么这应该可以:

    OneDependent.class.getResourceAsStream(resourcePath)
    

    【讨论】:

    • 我就是这么做的。它只显示了 Core JAR 所在的目录,而不是它的内容。
    • 试图理解你在说什么目录...... getResourceAsStream() 调用要么给你一个资源,要么如果它找不到资源则为 null。在你的情况下它会返回什么?
    • 我遍历了JSHookLoader.class.getClassLoader().getResources("");返回的内容
    【解决方案4】:

    我刚才也有类似的情况。我有一个“测试代码生成器”,它从 src/test/resources 目录中获取数据并将数据泵入 H2 数据库。从模块 A 可以正常工作,但是从模块 B 调用时却没有。它构造一个带有多个分号的路径(由于资源在 jar 文件中);然后 moduleA 无法找到“自身本地”的文件。

    最后我加了

        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
            </testResource>
            <testResource>
                <directory>../moduleA/src/test/resources</directory>
            </testResource>
        </testResources>
    

    到 moduleB 的构建部分,现在构建运行良好且符合预期。

    【讨论】:

      【解决方案5】:

      我认为这不是一个好主意。假设你有模块A。这取决于'B'。 “B”取决于C。基本上,您应该只关心A 中的B 模块的接口。或许,明天 它将依赖关系从C 更改为D。如果发生这种情况,您将需要更改 A。情况不是很好,是吗?所以以隐式方式声明依赖AC

      简而言之:如何访问依赖项的资源?

      简而言之:直接声明这个依赖。

      【讨论】:

      • 直接声明。我说的模块直接依赖于Core。
      猜你喜欢
      • 2020-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-15
      • 2016-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多