弹簧内部看不到jar中的文件

BTa*_*acs 82 spring jar classpath

所有

我在里面创建了一个包含以下MANIFEST.MF的jar文件:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.6.0_25-b06 (Sun Microsystems Inc.)
Main-Class: my.Main
Class-Path: . lib/spring-core-3.2.0.M2.jar lib/spring-beans-3.2.0.M2.jar
Run Code Online (Sandbox Code Playgroud)

在它的根目录中有一个名为my.config的文件,它在我的spring-context.xml中引用,如下所示:

<bean id="..." class="...">
    <property name="resource" value="classpath:my.config" />
</bean>
Run Code Online (Sandbox Code Playgroud)

如果我运行jar,除了加载特定文件外,一切看起来都很好:

Caused by: java.io.FileNotFoundException: class path resource [my.config] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/D:/work/my.jar!/my.config
        at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:205)
    at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52)
    at eu.stepman.server.configuration.BeanConfigurationFactoryBean.getObject(BeanConfigurationFactoryBean.java:32)
    at eu.stepman.server.configuration.BeanConfigurationFactoryBean.getObject(BeanConfigurationFactoryBean.java:1)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
    ... 22 more
Run Code Online (Sandbox Code Playgroud)
  • 类从jar内部加载
  • spring和其他依赖项从分隔的jar中加载
  • 加载了spring上下文(新的ClassPathXmlApplicationContext("spring-context/applicationContext.xml"))
  • my.properties加载到PropertyPlaceholderConfigurer("classpath:my.properties")
  • 如果我将.config文件放在文件系统之外,并将资源url更改为'file:',一切似乎都很好......

有小费吗?

sbk*_*sbk 164

如果你的spring-context.xml和my.config文件在不同的jar中,那么你需要使用classpath*:my.config

更多信息在这里

另外,确保在从jar文件中加载时resource.getInputStream()不使用resource.getFile().

  • ......这就是答案......谢谢!在jar内部不要使用resource.getFile():-) (51认同)
  • 再看一下,你的一些调用代码(可能是BeanConfigurationFactoryBean)正在尝试加载java.io.File.文件是指文件系统上的文件,而jar中的条目则不是.调用代码应该使用resource.getInputStream来加载jar. (12认同)
  • 而已.java.io.File表示文件系统中的目录结构中的文件.Jar是一个java.io.File.但是该文件中的任何内容都超出了java.io.File的范围.就java而言,直到它被解压缩,jar文件中的类与word文档中的单词没有区别. (5认同)
  • 除了resource.getInpuStream(),你还可以使用resource.getURL() (4认同)
  • 有没有可能是“为什么?” 后面没有在 jar 中使用 getFile() 吗?仅仅是文件位于 Jar 内部,因此“文件”就是 jar 文件吗? (2认同)

jma*_*ewt 36

我知道这个问题已经得到解答了.但是,对于那些使用spring boot的人来说,这个链接帮助了我 - https://smarterco.de/java-load-file-classpath-spring-boot/

然而,这resourceLoader.getResource("classpath:file.txt").getFile();导致了这个问题和sbk的评论:

而已.java.io.File表示文件系统中的目录结构中的文件.Jar是一个java.io.File.但是该文件中的任何内容都超出了java.io.File的范围.就java而言,直到它被解压缩,jar文件中的类与word文档中的单词没有区别.

帮助我理解为什么要使用getInputStream().它现在对我有用!

谢谢!


小智 22

在spring jar包中,我使用了新的ClassPathResource(filename).getFile(), which throws the异常:

无法解析为绝对文件路径,因为它不驻留在文件系统中:jar

但使用new ClassPathResource(filename).getInputStream()会解决这个问题.原因是jar中的配置文件不存在于操作系统的文件树中,因此必须使用getInputStream().


Rap*_*ael 5

错误消息是正确的(如果不是很有帮助):我们尝试加载的文件不是文件系统上的文件,而是 ZIP 中 ZIP 中的一大块字节。

通过实验(Java 11,Spring Boot 2.3.x),我发现它无需更改任何配置甚至通配符即可工作:

var resource = ResourceUtils.getURL("classpath:some/resource/in/a/dependency");
new BufferedReader(
  new InputStreamReader(resource.openStream())
).lines().forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

  • 这正是问题所在!谢谢! (2认同)