【发布时间】:2020-09-28 10:36:12
【问题描述】:
我正在尝试动态更新我的应用程序中的 @value 注释字段。
首先,这个应用程序有一个自定义属性源,源是Map<Object, String>。
启用计时器以在一分钟间隔后更新值。
package com.test.dynamic.config;
import java.util.Date;
import java.util.Map;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.util.StringUtils;
public class CustomPropertySorce extends EnumerablePropertySource<Map<String, Object>> {
public CustomPropertySorce(String name, Map<String, Object> source) {
super(name, source);
new java.util.Timer().schedule(new java.util.TimerTask() {
@Override
public void run() {
source.put("prop1", "yoyo-modified");
source.put("prop2", new Date().getTime());
System.out.println("Updated Source :" + source);
}
}, 60000);
}
@Override
public String[] getPropertyNames() {
// TODO Auto-generated method stub
return StringUtils.toStringArray(this.source.keySet());
}
@Override
public Object getProperty(String name) {
// TODO Auto-generated method stub
return this.source.get(name);
}
}
源Map<String, Object> 的初始值由PropertySourceLocator 提供。 (这不是真实的场景,但我正在尝试重新创建这里使用的逻辑)
package com.test.dynamic.config;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
public class CustomPropertySourceLocator implements PropertySourceLocator {
@Override
public PropertySource<?> locate(Environment environment) {
Map<String, Object> source=new HashMap<String,Object>(){{put("prop1","yoyo");put("prop2",new Date().getTime());}};
return new CustomPropertySorce("custom_source",source);
}
}
RestController 使用@Value 注入这些属性的类如下所示。
environment.getProperty("prop1"); 提供更新的值,但不是 @value 带注释的字段。
我还尝试使用environment.propertySources() 的addFirst 方法注入一个新的属性源updatedMap,假设它将优先于其他属性源。但这种努力也徒劳无功。任何线索都非常感谢。
package com.test.dynamic.config.controller;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DataController {
@Value("${prop1}")
private String propertyOne;
@Value("${prop2}")
private Long propertyTwo;
@Autowired
private ConfigurableEnvironment environment;
@GetMapping("/p1")
private String getProp1() {
System.out.println("~~~~>"+environment.getPropertySources());
environment.getPropertySources().forEach(ps -> {
if(ps.containsProperty("prop1") || ps.containsProperty("prop2")) {
System.out.println("*******************************************************");
System.out.println(ps.getName());
System.out.println(ps.getProperty("prop1"));
System.out.println(ps.getProperty("prop2"));
System.out.println("*******************************************************");
}
});
// env.get
return propertyOne;
// return environment.getProperty("prop1");
}
@GetMapping("/p2")
private Long getProp2() {
System.out.println("~~~~>"+environment.getPropertySources());
// env.get
return propertyTwo;
// return environment.getProperty("prop1");
}
@GetMapping("/update")
public String updateProperty() {
Map<String, Object> updatedProperties = new HashMap<>();
updatedProperties.put("prop1", "Property one modified");
MapPropertySource mapPropSource = new MapPropertySource("updatedMap", updatedProperties);
environment.getPropertySources().addFirst(mapPropSource);
return environment.getPropertySources().toString();
}
}
如果您认为这不是向RestController 注入值的正确方法,请告诉我。接受所有可能的替代建议/最佳做法。
【问题讨论】:
-
看看
java.util.concurrent.atomic.AtomicReference。我没有时间输入示例作为答案,但我用它来分享对具有变化值的Map的引用。 -
您也可以reload all properties使用执行器和云。为此,有注释
@RefreshScope。 -
@flaxel 我正在创建一个库。因此,我无法控制注入属性的 bean 的范围。 RefreshScope 表示“Spring Cloud 也引入了 RefreshScope,我们可以将其用于配置类或 bean。因此,默认范围将是刷新而不是单例。”
-
@Paul 您的意思是将“Map
source”包装在原子引用中吗?我想知道当负责保存值本身的“环境”显示更新的值时,这将如何提供帮助。 -
我试过 AtomicReference.... Map
initialSource = new HashMap(); initialSource.put("prop1","yoyo"); initialSource.put("prop2",new Date().getTime()); AtomicReference
标签: java spring spring-boot