问题描述:
最近在将项目部署到Linux环境下时,出现了加载spring.xml配置文件失败的问题,出错代码:
// Env.SPRING_PATH = /home/is/server/conf/spring.xml
springContext = new FileSystemXmlApplicationContext(Env.SPRING_PATH);
异常信息:
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from file [/home/is/server/lib/home/is/server/conf/spring.xml]; nested exception is java.io.FileNotFoundException: home/is/server/conf/spring.xml (No such file or directory)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:344)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:252)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)
at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129)
at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:613)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:514)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:140)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:84)
at com.is.Initializer.init(Initializer.java:36)
at com.is.launcher.App.main(App.java:44)
Caused by: java.io.FileNotFoundException: home/is/server/conf/spring.xml (No such file or directory)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at org.springframework.core.io.FileSystemResource.getInputStream(FileSystemResource.java:114)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:330)
... 19 more
看异常,意思是说找不到 /home/is/server/lib/home/is/server/conf/spring.xml 这个文件,但实际上传入的文件路径是“/home/is/server/conf/spring.xml”,那为什么spring中该文件路径会发生变化呢?而且报错的路径是home/is/server/conf/spring.xml (注意:这里没有了“/”)。
说明:
异常消息中,前面的路径“/home/is/server/lib”实际上是当前运行程序的路径,如果切换到其它目录则会变成相应路径。
看FileSystemXmlApplicationContext类代码发现:
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
该方法在获取资源时,会判断是否以“/”开头,如果是,则剥掉,导致Spring后续加载文件时使用的是不带“/”的文件路径,从而导致加载失败。
Why?
来看下getResourceByPath(String)方法的注释说明:
Resource org.springframework.context.support.FileSystemXmlApplicationContext.getResourceByPath(String path)
Resolve resource paths as file system paths.
Note: Even if a given path starts with a slash, it will get interpreted as relative to the current VM working directory. This is consistent with the semantics in a Servlet container.
注:即使给定的路径以斜线开始,它将会被解释为相对当前VM工作目录。这与servlet容器中的语义相一致。
应该就是为了和JavaWeb开发时的环境、用法保持一致吧。
解决方法:
继承FileSystemXmlApplicationContext,重写getResourceByPath(String)方法,如下:
springContext = new FileSystemXmlApplicationContext(Env.SPRING_PATH) {
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
// 忽略如下代码,使其在Linux环境能正常解析文件路径
// path = path.substring(1);
}
return new FileSystemResource(path);
}
};
OK,修改后可使用指定路径加载了!