Java @运行时的值
如何在运行时动态访问@Value机器 我原以为那个环境可能就是我要找的,但事实并非如此Java @运行时的值,java,spring,Java,Spring,如何在运行时动态访问@Value机器 我原以为那个环境可能就是我要找的,但事实并非如此 @Component public class SpringConfiguration implements ConfigurationI { @Autowired private Provider<Environment> env; @Override public String get(String key) { try {
@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;
}
}
}
PropertyPlaceholder
和朋友不会将属性放入您的环境中
(主要是因为向后兼容的原因)。相反,它们使用环境及其自身的内部属性
对象来解析@Value
属性,这些对象通常从类路径的属性文件中收集。因此,无法动态获取从PropertyPlaceholder加载的属性(即nogetProperty(String..)
)。
有些人创建自定义PropertyPlaceholder
,公开存储属性(通过getter或其他方式),但我认为这完全破坏了Spring新的统一环境配置处理
您真正想要的可能是@PropertySource
,它仍然非常糟糕,因为它不是动态的(因为它是一个注释,您无法更改文件从何处加载),但它会将属性加载到环境中。我一直想向Spring Source提交关于这一混乱的问题
无论如何,您可以在此处查看我的解决方案:
基本上,您需要掌握ConfigurableEnvironment
,并通过创建PropertySources
将您的属性加载到其中。这方面的API非常强大,但不是很直观。您可以使用ApplicationContextInitializers
获取有其自身恼人问题的环境
(请参见链接),也可以执行我下面所做的操作
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;
}
}
您的属性PlaceHolderConfigure
是如何配置的?我在问题中添加了一个示例。不幸的是,我们的配置设置没有存储在属性文件中。如果我们把它们储存在别的东西里,这对我有帮助吗?我是否必须尝试将所有配置文件塞入属性中,以便spring能够提供它们?因此,您不应该使用@PropertySource
,这正是我所抱怨的。看看我的另一个问题(链接)。您需要制作一个BeanDefinitionRegistryPostProcessor
,并配置环境
,您将在该环境中加载属性。我们有一个ApplicationContextInitializer
,它从多个位置(文件、数据库等)检索属性每个寄存器都有一个PropertySource
。工作非常好,因为它与Spring环境
很好地集成,因此@Value
之类的东西也能很好地集成。我在链接的问题中引用了我的问题与ApplicationContextInitializer
。使用ApplicationContextInitializer
时,您确实需要小心加载(包括日志记录)的内容,并且在没有意外预加载的情况下,无法使用许多spring内容。这是首选的规范方法(尽管Spring甚至没有将其用于@PropertySource..so…。@M.Deinum,只是为了与初始值设定项迭代更多的问题(慢慢记住)。您甚至不能使用SpringCore的大部分来设置ApplicationContextInitializer
,因为您将启动Commons日志记录。这包括整个资源
加载框架,请参阅。所以我可以想象,在db配置加载中,您一定使用了原始JDBC?
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;
}
}
public interface EnvironmentPropertiesMapSupplier {
public Map<String, String> getEnvironmentPropertiesMap();
}