如何构建自定义PropertySource以绑定到@ConfigurationProperties

时间:2015-07-16 13:52:22

标签: java spring-boot

我们正在创建一个使用数据库作为存储库的新PropertySource。我们的想法是我们可以在运行时更新属性值。

与此同时,我们希望使用@ConfigurationProperties,以便我们可以包含验证以及使用application- {profile}命名约定。

但是,似乎@ConfigurationProperties的值仅从“applicationConfig:[path / to / config]”PropertySource加载。例如,以下测试:

private final String OVERRIDEN_VALUE = "overriden value";

@Before
public void before() {

    LOGGER.debug("Property sources are: "); 
    for(Iterator<?> it = env.getPropertySources().iterator(); it.hasNext(); ) {
        PropertySource<?> propertySource = (PropertySource<?>) it.next();
        LOGGER.debug(propertySource.getName());
    }

    EnvironmentTestUtils.addEnvironment("integrationTest", env, "some.prefix.overridable-property=" + OVERRIDEN_VALUE);

}

@Test
public void testOverridingDefaultProperties() {

    LOGGER.debug("MutablePropertySources value: {}", env.getProperty("some.prefix.overridable-property"));
    LOGGER.debug("@ConfigurationProperties value: {}", testProperties.getOverridableProperty());

    Assert.assertEquals(OVERRIDEN_VALUE, testProperties.getOverridableProperty());

}

生成此输出:

Property sources are: 
    systemProperties
    systemEnvironment
    random
    integrationTest
    applicationConfig: [classpath:/path/to/my/application.yml]

MutablePropertySources value: overriden value
@ConfigurationProperties value: default value

有关更多上下文,我最初在Spring Boot的Github here上提出了这个问题。

1 个答案:

答案 0 :(得分:2)

感谢Spring Boot的人们。向我指出Spring Cloud Context

http://projects.spring.io/spring-cloud/spring-cloud.html#customizing-bootstrap-property-sources

看起来这样可以解决问题。

<强>更新

由于我们已经编写了额外的数据库支持的numeric_limits,我们实际上只需要在运行时刷新PropertySource。与此同时,我们并不想刷新所有@ConfigurationProperties。为了完成刷新,我们做了以下事情:

  1. 创建了一个名为@ConfigurationProperties
  2. 的注释
  3. 创建了以下使用Spring Boot @ReloadableProperties
  4. 的实用程序bean
    /**
     * 
     * Helper bean to reload {@code @ConfigurationProperties}
     * if the {@code @ConfigurationProperties} bean is annotated 
     * with {@code @ReloadableProperties}.
     * 
     * @author Jonathan Martin
     * @since 2.0.0
     * 
     * @see ReloadableProperties
     * @see ConfigurationPropertiesBindingPostProcessor
     *
     */
    public class ConfigurationPropertiesReloader {
    
        private final ApplicationContext context;
    
        private final ConfigurationPropertiesBindingPostProcessor processor;
    
        @Autowired
        public ConfigurationPropertiesReloader(ApplicationContext context,  ConfigurationPropertiesBindingPostProcessor processor) {
            this.context = context;
            this.processor = processor;
        }
    
        /**
         * Reload all {@code @ConfigurationProperties}
         * annotated with {@code @ReloadableProperties}.
         */
        public void reload() {
            Map beans = context.getBeansWithAnnotation(ReloadableProperties.class);
            for (Map.Entry entry : beans.entrySet()) {
    
                String beanName = entry.getKey();
                Object bean = entry.getValue();
    
                ConfigurationProperties annotation = AnnotationUtils.findAnnotation(bean.getClass(), ConfigurationProperties.class);
    
                // Only reload the bean if it's an @ConfigurationProperties
                // Can't check for instance of ConfigurationPropertiesHolder 
                // because it uses package scope.
                if (annotation != null) {
                    processor.postProcessBeforeInitialization(bean, beanName);
                }
    
            }
        }
    
    }
    
    

    现在,如果我将实用程序bean注入我的测试并调用reload,则测试通过。