Java 在JAR中加载属性文件?

Java 在JAR中加载属性文件?,java,maven-2,resources,properties,classloader,Java,Maven 2,Resources,Properties,Classloader,当我的web应用程序所依赖的一个jar试图从jar中加载属性文件时,我遇到了问题。下面是jar中的代码 static { Properties props = new Properties(); try { props.load(ClassLoader.getSystemResourceAsStream("someProps.properties")); } catch (IOException e) { e.print

当我的web应用程序所依赖的一个jar试图从jar中加载属性文件时,我遇到了问题。下面是jar中的代码

static
{
    Properties props = new Properties();
    try 
    {
        props.load(ClassLoader.getSystemResourceAsStream("someProps.properties"));
    } catch (IOException e) 
    {
        e.printStackTrace();
    }
    someProperty = props.getProperty("someKey");
}

属性文件位于Maven项目的“src/main/resources”目录中。当我在Eclipse中从junit测试运行这段代码时,它的执行情况很好。当项目使用Maven构建到jar中,并作为依赖项包含在我的web应用程序中时,它无法找到属性文件。我知道属性文件位于依赖jar的基本目录中,我不知道如何解决这个问题。

问题是您使用的是
getSystemResourceAsStream
。只需使用
getResourceAsStream
。系统资源从系统类加载器加载,这几乎肯定不是jar作为webapp运行时加载到的类加载器

它在Eclipse中工作,因为在启动应用程序时,系统类加载器配置了jar作为其类路径的一部分。(例如,java-jar my.jar将在系统类加载器中加载my.jar。)web应用程序并非如此——应用程序服务器使用复杂的类加载将web应用程序彼此隔离,并与应用程序服务器的内部隔离。例如,请参见和所使用的类加载器层次结构图

编辑:通常,您会调用
getClass().getResourceAsStream()
来检索类路径中的资源,但是当您在静态初始值设定项中获取资源时,您需要显式命名要从中加载的类加载器中的类。最简单的方法是使用包含静态初始值设定项的类, e、 g


作为记录,这记录在(单元测试中有说明,但同样适用于“常规”资源):

将资源添加到的类路径 在单元测试中,您遵循相同的步骤 与添加资源的方式相同 除了您要访问的目录之外,其他目录都可以访问JAR 将资源放在is中
${basedir}/src/test/resources
。在 这一点你会有一个项目 目录结构,看起来 例如:

my-app
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   |   `-- com
    |   |       `-- mycompany
    |   |           `-- app
    |   |               `-- App.java
    |   `-- resources
    |       `-- META-INF
    |           |-- application.properties
    `-- test
        |-- java
        |   `-- com
        |       `-- mycompany
        |           `-- app
        |               `-- AppTest.java
        `-- resources
            `-- test.properties
在单元测试中,您可以使用一个简单的 下面这样的代码片段 访问所需的资源 测试:

...

// Retrieve resource
InputStream is = getClass().getResourceAsStream("/test.properties" );

// Do something with the resource

...

另外,使用线程的上下文类加载器,如
thread.currentThread().getContextClassloader()
@binil感谢您的提示。我从来都不需要这样做——什么时候有必要?@binil——我已经对此进行了一些研究,并且理解了当您想要脱离类加载器的层次结构并使用一个不是您的类加载器祖先之一的类加载器时,上下文类加载器的使用。这里不需要上下文类加载器,因为资源位于同一个webapp中,因此与MyClass位于同一个类加载器中。在
test
main
中拥有资源是标准结构吗?这只是一个maven约定,还是JAR文档本身的一部分?@Thufir它是用于测试建模的……测试树中的资源从未打包到JAR中。JAR将只包含来自“源程序包”(src/main)的资源。
...

// Retrieve resource
InputStream is = getClass().getResourceAsStream("/test.properties" );

// Do something with the resource

...