如何在运行时动态访问@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公开的值。
编辑:为了解释我的用例:这是通过将spring特定的批注切换为JSR330 (javax.inject)批注,使包含大量spring特定部分(一堆较旧的Spring应用程序所依赖的)的库可以从较新的Guice应用程序中使用。我希望通过提供一个很好的入口点来避免在我们所有的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;
}
};
}发布于 2015-10-01 01:36:08
PropertyPlaceholder和朋友不会将属性放入您的Environment中(主要是因为向后兼容的原因)。相反,它们使用环境和它自己的内部Properties对象来解析@Value属性,这些对象通常从类路径中的属性文件中收集。因此,从PropertyPlaceholder加载的属性不能被动态获取(即没有getProperty(String..))。有些人创建定制的PropertyPlaceholder来公开存储属性(通过getter或其他方式),但我认为这完全破坏了Spring新的统一环境配置处理。
你真正想要的可能是@PropertySource,它仍然很糟糕,因为它不是动态的(因为它是一个注释,你不能改变文件的加载位置),但它会将属性加载到Environment中。我一直打算向Spring Source提交关于这方面的困惑的问题。
无论如何,您可以在这里查看我的解决方案:Manually add a @PropertySource: Configuring Environment before context is refreshed
基本上,您需要获取ConfigurableEnvironment并通过创建PropertySources将属性加载到其中。这方面的API非常强大,但不是很直观。你可以使用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,您就可以使用EnvironmentAware接口来处理需要环境的事情,也可以创建自己的接口。
下面是一个自定义接口,您可以使用它来处理需要动态属性的东西(上面的类实现了它):
public interface EnvironmentPropertiesMapSupplier {
public Map<String, String> getEnvironmentPropertiesMap();
}https://stackoverflow.com/questions/32870590
复制相似问题