带有注释的 Spring 4 PropertyPlaceholder

Posted

技术标签:

【中文标题】带有注释的 Spring 4 PropertyPlaceholder【英文标题】:Spring 4 PropertyPlaceholder with Annotations 【发布时间】:2014-05-09 20:29:56 【问题描述】:

好的,我知道这个问题已经被问过好几次了,我已经尝试了他们建议的答案中的每一个解决方案,但还没有找到一个有效的解决方案,所以我希望这里的人能指出我正确的方向。

我正在尝试将 Spring 4 与以 Java 为中心的配置一起使用,但在从属性文件加载属性时遇到问题。我的最新方法几乎是逐字遵循 Spring 的文档 here,但即使这样也行不通。

这是我的 properties-config.xml 文件(位于我的类路径上的 /config 目录中):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="
   http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-4.0.xsd">

   <context:property-placeholder location="classpath:db.properties"/>

</beans>

这是我的网络应用初始化程序类(一个 sn-p,无论如何):

public class TestWebAppInitializer implements WebApplicationInitializer

   @Override
   public void onStartup(ServletContext container)
   
      // Instantiate a new web application context
      AnnotationConfigWebApplicationContext appContext = 
            new AnnotationConfigWebApplicationContext();

      // Load the configurations
      appContext.scan("com.acme.config");
      appContext.refresh();

      // Add the dispatcher servlet
      ServletRegistration.Dynamic dispatcher =
            container.addServlet("dispatcher", new DispatcherServlet(appContext));
      dispatcher.setLoadOnStartup(1);

      // Add the various listeners
      container.addListener(new ContextLoaderListener(appContext));
      container.addListener(new RequestContextListener());
   

最后是一个使用属性文件的小示例配置类:

package com.acme.config;

@Configuration
@ImportResource("classpath:config/properties-config.xml")
public class HibernateConfiguration

   @Value("$jdbc.url")
   private String jdbcUrl;

   @Value("$jdbc.username")
   private String jdbcUsername;

   @Value("$jdbc.password")
   private String jdbcPassword;

   @Bean(name = "dataSource")
   public ComboPooledDataSource getDataSource() throws PropertyVetoException
   
      // Define a variable to hold the result
      ComboPooledDataSource ds = new ComboPooledDataSource();

      System.out.println("URL: " + jdbcUrl);
      System.out.println("Username: " + jdbcUsername);
      System.out.println("Password: " + jdbcPassword);

      // Set the properties for the data source
      ds.setJdbcUrl(jdbcUrl);
      ds.setUser(jdbcUsername);
      ds.setPassword(jdbcPassword);

      // Return the result
      return ds;
   

最后但同样重要的是,属性文件:

jdbc.url=jdbc:hsqldb:hsql://localhost/test
jdbc.username=myusername
jdbc.password=mypassword

System.out.println 语句对每个阻止我的数据源设置的值都返回“null”。

谁能告诉我我做错了什么?谢谢!

【问题讨论】:

您打算向properties-config.xml 添加内容吗?如果没有,您只需将@PropertySources 添加到@Configuration 类。 顺便说一句,你有类型。应该是`@Value("$jdbc.password")` 【参考方案1】:

终于找到了问题。实际上,有两个。首先,Bean 定义的顺序似乎很重要。一旦我将它们重新排序为更合适的顺序(即,首先创建 beanA,beanB 引用 beanA,beanC 引用 beanA 和 beanB),它似乎有所作为。

然而,主要问题是 HibernateConfiguration 类中有 PersistenceAnnotationBeanPostProcessor 的 Bean 定义。这个定义就是为什么 Environment 变量为 null 并且没有解析任何属性的原因。

感谢@Artem Bilan 的所有帮助!

【讨论】:

BeanPostProcessors 必须配置为 static @Bean 并且正确,它们不应该与其他 bean 有任何依赖关系。用static 标记它们允许首先配置BPP,然后才配置所有其他内容:其他bean 的自动装配、属性占位符等 我对此赞不绝口。这正是我的问题。是的,当使用休眠时,我也使用 PersistenceAnnotationBeanPostProcessor,但是没有其他解决方案提到这个 bean 也必须是静态的。这是有道理的,但直到现在才明显。非常感谢! “订购”的事情让我头疼了好几个小时。真的很失望,这并不容易配置。阅读此答案后,终于可以正常工作了。【参考方案2】:

真正的问题是注解配置是在任何导入的 XML 之前加载的,您确实必须将属性占位符配置移动到 @Configuration

@Configuration    
@PropertySource("classpath:db.properties")
public class HibernateConfiguration 

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

请注意propertySourcesPlaceholderConfigurer bean 的定义。没有它,您只能使用自动连接的Environment 从文件中访问您的属性。

从这里开始,属性占位符配置也可用于导入的 xml。

更多信息参见PropertySourceJavaDocs

【讨论】:

所以这是许多其他线程提供的最常见的解决方案之一,但它仍然对我不起作用。我将“@ImportResource”注释更改为“@PropertySource”并将其指向“classpath:db.properties”并添加了静态 PropertySourcesPlaceholderConfigurer 方法,但没有运气。那我读错了Spring文档吗?我以为我每行都在跟踪它? classpath:db.properties 真的是正确的路径吗?您真的使用该文件中的正确密钥吗? 是的,它是正确的路径,是的,如您所见,键是正确的 - 我已修正错字,谢谢!当我有一个纯 XML 配置时,这是提供正确工作路径的部分:&lt;bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&gt; &lt;property name="ignoreUnresolvablePlaceholders" value="false" /&gt; &lt;property name="location" value="classpath:db.properties" /&gt; &lt;/bean&gt; 好的。我建议你调试你的应用程序:看看Environmet 有什么;尝试使用PropertiesFactoryBean 加载您的文件。顺便说一句,你用@Bean 标记了propertySourcesPlaceholderConfigurer() 吗? 是的,我已经完全按照上面的方式标记了它。

以上是关于带有注释的 Spring 4 PropertyPlaceholder的主要内容,如果未能解决你的问题,请参考以下文章

带有 spring 注释方法的 Java .parallelStream()

带有 @EnableJpa* 注释的 Spring @WebMvcTest

带有注释的 Spring + Hibernate:没有 Hibernate Session 绑定到线程

如何为带有注释的 spring 设置 context.xml?

带有注释的 Spring MVC 验证

带有 PropertyPlaceholderConfigurer bean 的 Spring @Configuration 文件不解析 @Value 注释