【问题标题】:Spring 3.1 Environment does not work with user property filesSpring 3.1 环境不适用于用户属性文件
【发布时间】:2013-01-05 07:52:15
【问题描述】:

我正在这样做..

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(context);
xmlReader
        .loadBeanDefinitions(new ClassPathResource("SpringConfig.xml"));
PropertySourcesPlaceholderConfigurer propertyHolder = new PropertySourcesPlaceholderConfigurer();
propertyHolder.setLocation(new ClassPathResource(
        "SpringConfig.properties"));
context.addBeanFactoryPostProcessor(propertyHolder);

    ......

context.refresh();

现在在我的@Configuration 文件中,如果我这样做,我的 SpringConfig.properties 中的属性不会被拾取...

@Autowired
private Environment env
.....
env.getProperty("my.property")

但是如果我使用,我会得到那个属性

@Value("${my.property}")
private String myProperty;

我什至尝试像这样添加更多行,但没有用。

ConfigurableEnvironment env = new StandardEnvironment();
propertyHolder.setEnvironment(env);

有人知道为什么我的属性没有加载到环境中吗?谢谢。

【问题讨论】:

    标签: java spring


    【解决方案1】:

    PropertySourcesPlaceholderConfigurer 直接读取属性文件(就像在 Spring 3.0 中由 PropertyPlaceholderConfigurer 所做的那样),它只是一个后处理器,不会改变在 Spring 上下文中使用属性的方式 - 在这种情况下,属性只能用作 bean 定义占位符.

    使用 Environment 的是 PropertySourcesPlaceholderConfigurer,反之则不然。

    属性源框架在应用程序上下文级别上工作,而属性占位符配置器仅提供处理 bean 定义中的占位符的功能。要使用属性源抽象,您应该使用 @PropertySource 注释,即用类似的东西装饰您的配置类 @PropertySource("classpath:SpringConfig.properties")

    我相信您可以以编程方式执行相同的操作,即您可以在刷新上下文之前获取容器的 ConfigurableEnvironment,修改其 MutablePropertySources(您需要首先通过 context.getEnvironment() 获取 AbstractApplicationContext environment 属性)通过 @ 987654330@ 但这不太可能是您想要做的 - 如果您已经有一个 @Configuration 注释类,用 @PropertySource("classpath:SpringConfig.properties") 装饰它要简单得多。

    至于 PropertySourcesPlaceholderConfigurer 实例 - 它会自动从其应用程序上下文中获取属性源(因为它实现了 EnvironmentAware),因此您只需注册它的默认实例。

    自定义属性源实现示例见http://blog.springsource.org/2011/02/15/spring-3-1-m1-unified-property-management/

    【讨论】:

    • 我通过了 MutuablePropertySources API,但它真的很混乱,我觉得 Spring 并没有让属性处理变得简单和美观。但是你说我不太可能这样做,为什么不呢?如果它有效,我可以尝试。我认为我的属性会在环境中的原因是在阅读了这篇文章之后.. http://www.javaworld.com/community/node/8309
    • @user1364959 请检查blog.springsource.org/2011/02/15/… - P.S.我说“不太可能”,因为仅仅用 @PropertySource("classpath:SpringConfig.properties") 装饰你的 Conifuguration 类就足以将属性源添加到环境中。
    • 对于 PropertySourcesPlaceholderConfigurer - 当您在容器中注册一个类似 @Bean() public static PropertySourcesPlaceholderConfigurer() {..} 的东西时,它会自动从应用程序上下文中获取属性源(因为它实现了 EnvironmentAware)。因此它将能够替换 bean 定义中的占位符。
    • 至于编程替代部分(即不使用@PropertySources 注释) - 我只是查看了 ConfigurationClassParser.processConfigurationClass 和 ConfigurationClassPostProcessor.processConfigBeanDefinitions 的来源 - 感谢 STS/Eclipse 的“Java 搜索”功能。这就是在 Spring 框架中完成的方式,我认为没有更简单的替代方案。
    • 也许您可以尝试使用 addLast 而不是 addFirst 或类似的东西 - 这样系统属性将首先被处理。
    【解决方案2】:

    local 属性添加到 PropertySourcesPlaceholderConfigurer(使用 setProperties()setLocation())不会使它们在 Environment 中可用。

    实际上它以相反的方式工作 - Environment 充当属性的主要来源(请参阅 ConfigurableEnvironment),PropertySourcesPlaceholderConfigurer 可以使用 Environment 语法使来自 Environment 的属性可用。

    【讨论】:

      【解决方案3】:

      我按照@Boris 的建议做了这个。

          PropertySourcesPlaceholderConfigurer propertyHolder = new PropertySourcesPlaceholderConfigurer();
          ConfigurableEnvironment env = new StandardEnvironment();
          env.getPropertySources().addFirst(
                  new ResourcePropertySource(new ClassPathResource(
                          "SpringConfig.properties")));
          propertyHolder.setEnvironment(env);
          context.addBeanFactoryPostProcessor(propertyHolder);
                  context.register(SpringConfig.class);
                  context.refresh();
      

      现在在@Configuration 类中,所有属性(包括我自己的和系统属性)都可以使用@Value 解析。

      但是将@Autowired 引入@Configuration 类的环境中只有系统属性,而不是我上面设置的SpringConfig.properties。但很明显,在上面调用context.refresh() 之前,ConfigurableEnvironment 也有我的属性。但是一旦调用了context.refresh(),我的属性就会从自动装配到@Configuration 的环境中删除。

      我希望能够使用更好的语法 env.getProperty("my.property")。有人知道为什么会这样吗?

      【讨论】:

      • 您不应创建自己的环境实例。您应该修改应用程序上下文具有的那个。附言请编辑问题而不是将其作为答案发布。
      • ...如果您通过@Configuration 创建自己的应用程序上下文?
      【解决方案4】:

      我正在加载 2 种类型的属性,一种是 Environment 属性,另一种是您通常从 servletContext.getServletContext() 获得的上下文。 我的环境属性定义为:MOD_CONFIG_ROOT,它在环境中单独设置,从而将包含代码的 ear 文件的位置详细信息分开。这是配置。 [注意:在加载 servlet 之前,我必须首先加载属性文件以使用 ${someProperty} 的属性]

      <bean id="externalProperties"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
          <property name="locations">
              <list>
                  <value>file:#{ systemEnvironment['MOD_CONFIG_ROOT']
                      }#{servletContext.contextPath}/users.properties</value>
              </list>
          </property>
          <property name="searchSystemEnvironment" value="true" />
          <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_FALLBACK" />
      </bean>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-26
        • 2015-11-22
        • 2018-03-22
        • 2021-02-01
        • 2018-08-08
        • 2017-10-31
        • 1970-01-01
        • 2012-06-06
        相关资源
        最近更新 更多