Недавно я был озадачен тем, что, как я думал, будет довольно простой реализацией — рассмотрим следующий файл определения bean-компонента на основе Spring Java (
@ Конфигурация ):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
package root; ... @Configuration @PropertySource ( "classpath:root/test.props" ) public class SampleConfig { @Value ( "${test.prop}" ) private String attr; @Bean public SampleService sampleService() { return new SampleService(attr); } } |
Здесь определяется bean-компонент `sampleService`, этот bean-компонент инициализируется атрибутом, который заполняется с помощью аннотации @Value с использованием строки-заполнителя свойства $ {test.prop}.
Тест для этого заключается в следующем:
01
02
03
04
05
06
07
08
09
10
|
@ContextConfiguration (classes=SampleConfig. class ) @RunWith (SpringJUnit4ClassRunner. class ) public class ConfigTest { @Autowired private SampleService sampleService; @Test public void testConfig() { assertThat(sampleService.aMethod(), is( "testproperty" )); } } |
который в текущей реализации SampleConfig завершается неудачей, так как заполнитель $ {test.prop} не разрешается вообще. Стандартное исправление для этого заключается в регистрации PropertySourcesPlaceholderConfigurer, который является BeanFactoryPostProcessor, отвечающим за сканирование всех зарегистрированных определений bean-компонентов и внедрение в разрешенные заполнители. С этим изменением на месте файл @Configuration выглядит так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@Configuration @PropertySource ( "classpath:root/test.props" ) public class SampleConfig { @Value ( "${test.prop}" ) private String attr; @Bean public SampleService sampleService() { return new SampleService(attr); } @Bean public PropertySourcesPlaceholderConfigurer placeHolderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } } |
Однако после добавления в распознаватель свойств тест все равно не пройден, на этот раз значение, возвращаемое sampleService, равно нулю, даже не значение заполнителя!
Причиной этой проблемы, как выясняется, является то, что в @Configuration, которая внутренне использует аннотации, такие как @Autowired, @Value и @PostConstruct, любые bean-компоненты BeanFactoryPostProcessor должны быть объявлены с помощью статического модификатора. В противном случае содержащийся класс @Configuration создается очень рано, и BeanPostProcessors, отвечающие за разрешение аннотаций, таких как @Value, @Autowired и т. Д., Не могут на него воздействовать.
Это исправление хорошо документировано в javadoc @Bean , кроме того, также регистрируется сообщение, которое предоставляет обходной путь:
1
|
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 |
Итак, с этим исправлением новая рабочая конфигурация выглядит следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@Configuration @PropertySource ( "classpath:root/test.props" ) public class SampleConfig { @Value ( "${test.prop}" ) private String attr; @Bean public SampleService sampleService() { return new SampleService(attr); } @Bean public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } } |
Рекомендации:
- Jira запись по этому вопросу
- @ Bean Javadoc
- Связанная проблема в Stackoverflow