@Value在运行时

时间:2015-09-30 15:54:50

标签: java spring

如何在运行时动态访问@Value机器?

我认为环境可能就是我想要的,但它

@Component
public class SpringConfiguration implements ConfigurationI {
    @Autowired
    private Provider<Environment> env;

    @Override
    public String get(String key) {
        try {
            return env.get().getRequiredProperty(key);
        } catch (IllegalStateException e) {
            return null;
        }
    }
}

不幸的是,这不会访问我们的PropertyPlaceholderConfigurer bean公开的值。

编辑:解释我的用例:这是通过切换JSR 330的Spring特定注释,使用大量弹簧特定部分(一堆较旧的Spring应用程序所依赖的)从新的Guice应用程序中使用的库的一部分( javax.inject)的。我希望通过提供这样一个很好的入口点来避免重写所有Spring应用程序中的所有PropertyPlaceholderConfigurer内容。如果有另一种更好的方法可以做到这一点(也许是@Named?)那么我全都听见了。

EDIT2:这是一个(清理过的)示例,说明调用此库的应用程序中存在哪种PropertyPlaceholderConfigurer。

@Bean
public PropertyPlaceholderConfigurer placeholderConfigurer() {
    return new PropertyPlaceholderConfigurer() {
        @Override
        protected String resolvePlaceholder(String placeholder, Properties props) {
            // Some code to parse and cleanup key here
            String result = getPropertyFromLocalAppSpecificConfig(key);
            if (result == null) {
                result = super.resolvePlaceholder(placeholder, props);
            }
            // Some more random app specific logic for missing defaults
            return result;
        }
    };
}

1 个答案:

答案 0 :(得分:0)

PropertyPlaceholder和朋友不会将属性放在Environment中(主要是因为向后兼容的原因)。相反,他们使用Environment及其自己的内部Properties对象,这些对象通常从类路径的属性文件中收集,以解析@Value属性。因此,无法动态获取从PropertyPlaceholder加载的属性(即没有getProperty(String..))。 有些人创建自定义PropertyPlaceholder来公开存储属性(通过getter或其他),但我认为完全违背了Spring的新统一环境配置处理。

你真正想要的可能是@PropertySource,它仍然非常糟糕,因为它不是动态的(因为它是一个注释你不能改变加载文件的位置)但是它会将属性加载到{{ 1}}。我一直想向Spring Source提出有关此问题的疑问。

无论如何,你可以在这里查看我的解决方案:Manually add a @PropertySource: Configuring Environment before context is refreshed

基本上,您需要抓住Environment并通过创建ConfigurableEnvironment将属性加载到其中。这个API非常强大,但不是很直观。您可以使用PropertySources来获取有{(1}}的问题(请参阅链接),或者您可以执行以下操作。

ApplicationContextInitializers

加载Environment后,您可以将public class ConfigResourcesEnvironment implements ResourceLoaderAware, EnvironmentAware, BeanDefinitionRegistryPostProcessor, EnvironmentPropertiesMapSupplier { private Environment environment; private Map<String, String> environmentPropertiesMap; @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { if (environment instanceof ConfigurableEnvironment) { ConfigurableEnvironment env = ((ConfigurableEnvironment) this.environment); List<PropertySource> propertySources; try { propertySources = loadPropertySources(); //Your custom method for propertysources } catch (IOException e) { throw new RuntimeException(e); } //Spring prefers primacy ordering so we reverse the order of the sources... You may not need to do this. reverse(propertySources); for (PropertySource rp : propertySources) { env.getPropertySources().addLast(rp); } environmentPropertiesMap = ImmutableMap.copyOf(environmentPropertiesToMap(env)); } else { environmentPropertiesMap = ImmutableMap.of(); } } public static Map<String,String> environmentPropertiesToMap(ConfigurableEnvironment e) { Map<String, String> properties = newLinkedHashMap(); for (String n : propertyNames(e.getPropertySources())) { String v = e.getProperty(n); if (v != null) properties.put(n, v); } return properties; } public static Iterable<String> propertyNames(PropertySources propertySources) { LinkedHashSet<String> propertyNames = new LinkedHashSet<String>(); for (PropertySource<?> p : propertySources) { if (p instanceof EnumerablePropertySource) { EnumerablePropertySource<?> e = (EnumerablePropertySource<?>) p; propertyNames.addAll(asList(e.getPropertyNames())); } } return propertyNames; } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { //NOOP } @Override public void setEnvironment(Environment environment) { this.environment = environment; } public Map<String, String> getEnvironmentPropertiesMap() { return environmentPropertiesMap; } } 界面用于需要环境的内容或创建自己的界面。

这是一个自定义界面,可用于需要动态属性的东西(上面的类实现它):

ConfigurableEnvironment