【问题标题】:Why does Spring's PropertySource throw a FileNotFoundException?为什么 Spring 的 PropertySource 会抛出 FileNotFoundException?
【发布时间】:2016-11-11 03:18:59
【问题描述】:

我正在尝试使用 Spring 加载属性文件,该文件位于我的 WEB-INF 文件夹中。

我收到以下错误:

org.springframework.beans.factory.BeanDefinitionStoreException: 失败 解析配置类[com.elastictest.config.ProdConfig]; 嵌套异常是 java.io.FileNotFoundException: \WEB-INF\config\prod.properties(系统找不到路径 指定)

这是我的生产配置文件:

@Configuration
@Profile("prod")
@PropertySource("file:${prodPropertiesFile}")
public class ProdConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

}

这是我的 web.xml 声明:

<context-param>
    <param-name>prodPropertiesFile</param-name>
    <param-value>/WEB-INF/config/prod.properties</param-value>
</context-param>

我已经打开了战争并验证了属性文件在 WEB-INF/config 文件夹下。有什么想法吗?

【问题讨论】:

    标签: java spring-mvc


    【解决方案1】:

    您在@PropertySource 注释中指定的locationsResourceLoader 处理。在这种情况下,这将是您的 AnnotationConfigWebApplicationContext,因为这是一个 Web 应用程序并且您想要使用注释配置。

    作为ResourceLoader 实现,AnnotationConfigWebApplicationContext 知道如何解析location 值以查找和初始化Resource 对象。它使用这些来创建用于属性解析的ResourcePropertySource 对象。

    location 值解析遵循几个步骤:

    • 如果它以/ 开头,它会被解释为一个servlet 上下文资源,Spring 会尝试通过ServletContext#getResourceAsStream 检索它。

    • 如果它以classpath: 开头,它被解释为一个类路径资源,Spring 尝试通过ClassLoader#getResourceAsStream 检索它,给定一个适当的ClassLoader

    • 否则,它会将解析推迟到使用URL 来定位资源的UrlResource。它的 javadoc 状态

      "file:" 协议的情况下支持URLFile 的分辨率。

    在您的情况下,您的位置前缀为 file:,因此 Spring 尝试使用 UrlResource。您的路径有一个前导 /,文件系统会将其视为绝对路径的开始。你显然在那个位置没有文件,/WEB-INF/config/prod.properties

    如果您按照this answer 中的建议使用classpath: 前缀,那么您必须确保/WEB-INF/config/prod.properties 在类路径中。放在类路径上是一件非常不常见的事情,所以我不推荐它。

    最后,正如你所发现的,你可以使用

    @PropertySource("/WEB-INF/config/prod.properties")
    // or to support your property
    @PropertySource("${prodPropertiesFile}")
    

    它将尝试通过ServletContext 检索资源。它的 javadoc 状态

    路径必须以/ 开头并被解释为相对于当前上下文根

    您的WEB-INF 文件夹将位于上下文根目录(基本上是为您的 Servlet 容器选择的目录作为您的 Web 应用程序的根目录),因此将找到并使用该资源。


    您可以在官方文档here 中阅读有关Resource 的更多信息,以及有关ResourceLoader 流程here 的更多信息。

    【讨论】:

    • 对 OP 和我来说也是很好的解释。我不太擅长写作和解释:)
    【解决方案2】:

    不需要 web.xml 声明。像这样试试

    @PropertySource(name="prodPropertiesFile", value="classpath:/WEB-INF/config/prod.properties")
    public class ProdConfig {
    }
    

    【讨论】:

    • 如果我删除上下文参数的 wen.xml 声明,prodPropertiesFile 将引用什么
    • 你试试我的方法吗?春天不需要 4.你有名字和价值。你可以使用名字。检查docs.spring.io/spring/docs/current/javadoc-api/org/…
    • 是的,我试过了,结果一样。我真的被这个难住了
    • 您的建议会有什么不同?他们的尝试有什么问题?你的哪一点是正确的?你为什么认为资源在classpath
    • 我已经发布了一个详细说明所有内容的答案。这就是我要你回答的问题。解释为什么他们的不起作用,为什么你的会。在他们的情况下,我认为不会。他们没有显示任何证据表明 /WEB-INF/config/prod.properties 会在类路径上,我不明白他们为什么会这样做。
    【解决方案3】:

    事实证明它比我做的更简单:

    @PropertySource("/WEB-INF/config/prod.properties")
    

    【讨论】:

      猜你喜欢
      • 2013-12-08
      • 2016-03-04
      • 2015-11-09
      • 2022-10-07
      • 2013-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多