最近,我被我认为将是一个相当简单的实现所困扰-考虑以下基于Spring Java的bean定义文件(
@Configuration ):
package root;...@Configuration
@PropertySource("classpath:root/test.props")
public class SampleConfig {@Value("${test.prop}")private String attr;@Beanpublic SampleService sampleService() {return new SampleService(attr);}
}
此处定义了一个bean“ sampleService”,该bean初始化为一个属性,该属性使用@Value注释(使用属性占位符字符串$ {test.prop})填充。
对此的测试如下:
@ContextConfiguration(classes=SampleConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ConfigTest {@Autowiredprivate SampleService sampleService;@Testpublic void testConfig() {assertThat(sampleService.aMethod(), is("testproperty"));}
}
由于占位符$ {test.prop}根本无法解析,因此使用SampleConfig的当前实现会失败。 为此的标准解决方法是注册一个PropertySourcesPlaceholderConfigurer ,它是一个BeanFactoryPostProcessor,负责扫描所有已注册的bean定义并注入已解析的占位符。 进行此更改后,@ Configuration文件如下所示:
@Configuration
@PropertySource("classpath:root/test.props")
public class SampleConfig { @Value("${test.prop}")private String attr;@Beanpublic SampleService sampleService() {return new SampleService(attr);}@Beanpublic PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {return new PropertySourcesPlaceholderConfigurer();}
}
但是,在添加了属性解析器后,测试仍然失败,这一次sampleService返回的值为null,甚至没有占位符值!
导致该问题的原因是,在@Configuration内部使用诸如@ Autowired,@ Value和@PostConstruct之类的批注的情况下,任何BeanFactoryPostProcessor Bean都必须使用static修饰符进行声明。 否则,包含的@Configuration类将在很早之前实例化,并且负责解析诸如@ Value,@ Autowired等注释的BeanPostProcessors无法对其执行操作。
此修复程序在@Bean的javadoc中有详细记录,还记录了一条消息,提供了解决方法:
WARN : org.springframework.context.annotation.ConfigurationClassEnhancer - @Bean method RootConfig.placeHolderConfigurer is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean Javadoc for complete details
因此,使用此修复程序,新的工作配置如下:
@Configuration
@PropertySource("classpath:root/test.props")
public class SampleConfig { @Value("${test.prop}")private String attr;@Beanpublic SampleService sampleService() {return new SampleService(attr);}@Beanpublic static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {return new PropertySourcesPlaceholderConfigurer();}
}
参考文献:
- 吉拉记录本期
- @Bean Javadoc
- Stackoverflow中的相关问题
翻译自: https://www.javacodegeeks.com/2013/07/spring-bean-and-propertyplaceholderconfigurer.html