所有
我创建了一个jar文件,里面有以下MANIFEST.MF:
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
在它的根目录中有一个名为my.config的文件,它在我的spring-content.xml中被引用,如下所示:
<bean id="..." class="...">
<property name="resource" value="classpath:my.config" />
</bean>
如果我运行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
- 类从jar中加载
- spring和其他依赖项是从分离的jar加载的
- 加载spring上下文(新的ClassPathXmlApplicationContext("spring-context/applicationContext.xml"))
- my.properties加载到PropertyPlaceholderConfigurer中("classpath:my.properties")
- 如果我将.config文件放在文件系统之外,并将资源url更改为"file:",那么一切似乎都很好
有什么建议吗?
如果您的spring-content.xml和my.config文件位于不同的jar中,则需要使用classpath*:my.config
?
更多信息点击这里
此外,请确保从jar文件内部加载时使用的是resource.getInputStream()
而不是resource.getFile()
。
在spring-jar包中,我使用了新的ClassPathResource(filename).getFile()
,它抛出了异常:
无法解析为绝对文件路径,因为它不存在于文件系统中:jar
但使用new ClassPathResource(filename).getInputStream()
可以解决这个问题。原因是jar中的配置文件在操作系统的文件树中不存在,所以必须使用getInputStream()
。
我知道这个问题已经得到了回答。然而,对于那些使用弹簧靴的人来说,这个链接帮助了我——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无法访问的注意,在解压缩之前,jar文件中的类是no与word文档中的单词不同。
帮助我理解了为什么使用getInputStream()
。它现在对我有效!
谢谢!
错误消息是正确的(如果不是很有用的话):我们试图加载的文件不是文件系统上的文件,而是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);
我在Spring应用程序中递归加载资源时遇到问题,发现问题是我应该使用resource.getInputStream
。下面是一个示例,展示了如何递归地读入config/myfiles
中的所有文件(即json
文件)。
示例.java
private String myFilesResourceUrl = "config/myfiles/**/";
private String myFilesResourceExtension = "json";
ResourceLoader rl = new ResourceLoader();
// Recursively get resources that match.
// Big note: If you decide to iterate over these,
// use resource.GetResourceAsStream to load the contents
// or use the `readFileResource` of the ResourceLoader class.
Resource[] resources = rl.getResourcesInResourceFolder(myFilesResourceUrl, myFilesResourceExtension);
// Recursively get resource and their contents that match.
// This loads all the files into memory, so maybe use the same approach
// as this method, if need be.
Map<Resource,String> contents = rl.getResourceContentsInResourceFolder(myFilesResourceUrl, myFilesResourceExtension);
ResourceLoader.java
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.StreamUtils;
public class ResourceLoader {
public Resource[] getResourcesInResourceFolder(String folder, String extension) {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
String resourceUrl = folder + "/*." + extension;
Resource[] resources = resolver.getResources(resourceUrl);
return resources;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public String readResource(Resource resource) throws IOException {
try (InputStream stream = resource.getInputStream()) {
return StreamUtils.copyToString(stream, Charset.defaultCharset());
}
}
public Map<Resource, String> getResourceContentsInResourceFolder(
String folder, String extension) {
Resource[] resources = getResourcesInResourceFolder(folder, extension);
HashMap<Resource, String> result = new HashMap<>();
for (var resource : resources) {
try {
String contents = readResource(resource);
result.put(resource, contents);
} catch (IOException e) {
throw new RuntimeException("Could not load resource=" + resource + ", e=" + e);
}
}
return result;
}
}
我在使用Tomcat6.x时遇到了类似的问题,我发现的建议都没有帮助。最后,我删除了(Tomcat的)work
文件夹,问题就消失了。
我知道这是不合逻辑的,但出于文件目的。。。
对于kotlin用户,我是这样解决的:
val url = ResourceUtils.getURL("classpath:$fileName")
val response = url.openStream().bufferedReader().readText()
@sbk的答案是,在我看来,我们应该在春季启动环境中(除了@Value("${classpath*:}))执行它。但在我的场景中,如果从独立jar执行,它就不起作用。可能是我做错了什么。
但这可能是另一种方法,
InputStream is = this.getClass().getClassLoader().getResourceAsStream(<relative path of the resource from resource directory>);
我遇到了一个更复杂的问题,因为我有多个同名文件,一个在主Spring Boot jar中,其他在主fat jar中。我的解决方案是获得所有具有相同名称的资源,然后获得我需要按包名称筛选的资源。获取所有文件:
ResourceLoader resourceLoader = new FileSystemResourceLoader();
final Enumeration<URL> systemResources = resourceLoader.getClassLoader().getResources(fileNameWithoutExt + FILE_EXT);
在Spring boot 1.5.22.RELEASE Jar包装中,这对我来说很有效:
InputStream resource = new ClassPathResource("example.pdf").getInputStream();
"example.pdf";位于src/main/resources中。
然后将其读取为字节[]
FileCopyUtils.copyToByteArray(resource);
我遇到了同样的问题,最终使用了更方便的Guava资源:
Resources.getResource("my.file")
虽然这是一个非常旧的线程,但我在Spring Boot应用程序中添加FCM时也遇到了同样的问题。
在开发过程中,文件被打开,没有任何错误,但当我将应用程序部署到AWS Elastic beanstall时,FileNotFoundException
的错误被抛出,FCM无法工作。
因此,这里是我的解决方案,使它在开发环境和jar部署生产中都能工作。
我有一个组件类FCMService,它有一个方法如下:
@PostConstruct
public void initialize() {
log.info("Starting FCM Service");
InputStream inputStream;
try {
ClassPathResource resource = new ClassPathResource("classpath:fcm/my_project_firebase_config.json");
URL url = null;
try {
url = resource.getURL();
} catch (IOException e) {
}
if (url != null) {
inputStream = url.openStream();
} else {
File file = ResourceUtils.getFile("classpath:fcm/my_project_firebase_config.json");
inputStream = new FileInputStream(file);
}
FirebaseOptions options = FirebaseOptions.builder().setCredentials(GoogleCredentials.fromStream(inputStream))
.build();
FirebaseApp.initializeApp(options);
log.info("FCM Service started");
} catch (IOException e) {
log.error("Error starting FCM Service");
e.printStackTrace();
}
}
希望这能帮助那些寻求实现FCM的快速解决方案的人。
可以像一样处理
var serviceAccount = ClassLoader.getSystemResourceAsStream(FB_CONFIG_FILE_NAME);
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.build();
其中FB_CONFIG_FILE_NAME是"资源"文件夹中的文件名。