如何在运行时动态访问@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 特定部分(一堆旧 Spring 应用程序所依赖)的库的一部分,可以通过切换 JSR 330 的 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;
}
};
}
最佳答案
PropertyPlaceholder
和 friend 不会将属性放入您的Environment
中(主要是因为向后兼容性原因)。相反,它们使用环境及其自己的内部 Properties
对象(通常从类路径的属性文件中收集)来解析 @Value
属性。因此,无法动态获取从 PropertyPlaceholder 加载的属性(即没有 getProperty(String..)
)。
有些人创建自定义 PropertyPlaceholder
来公开存储属性(通过 getter 或其他方式),但我认为完全击败了 Spring 新的统一环境配置处理。
您真正想要的可能是 @PropertySource
,它仍然非常糟糕,因为它不是动态的(因为它是一个注释,您无法更改文件的加载位置),但它会将属性加载到环境
。我一直想向 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
接口(interface)来处理需要环境的事物或创建您自己的接口(interface)。
这是一个自定义接口(interface),您可以将其用于需要动态属性的事物(上面的类实现了它):
public interface EnvironmentPropertiesMapSupplier {
public Map<String, String> getEnvironmentPropertiesMap();
}
关于java - @运行时的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32870590/