1, 前面我们写了使用自定义的加载properties 的代码
里面实现了 EnvironmentPostProcessor
代码语言:javascript复制@Override
代码语言:javascript复制public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
environment.getPropertySources().addLast(new MapPropertySource(FILE_PATH, mapPropertySource()));
}
也就是说我们手动实现这个也就可以添加环境变量, 由于是MapPropertySource , 相同的key 会覆盖。
代码。
下面我们开看刷新Environment 的代码实现
代码语言:javascript复制 public static void refreshEnvironment(Map<String, Object> map,ConfigurableEnvironment configurableEnvironment) {
MutablePropertySources mutablePropertySources = configurableEnvironment.getPropertySources();
// 添加远程配置信息
mutablePropertySources.addFirst(new MapPropertySource("remoteConfig", map));
}
刷新玩Environment ,在刷新Bean 对象,利用field 属性通过反射
有两个值, 一个是Bean 对象,一个是ConfigurablePropertyResolver 配置文件参数分解器。
获取bean 的field 的属性看上面有没有@Value注解,根据注解的值和field的type 获取field 的值在从新的赋值。
具体代码
代码语言:javascript复制public static void refreshBean(Object bean, ConfigurablePropertyResolver propertyResolver) {
// 定义EL表达式解释器
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
TemplateParserContext templateParserContext= new TemplateParserContext();
String keyResolver, valueResolver = null;
Object parserValue;
// 获取真实对象属性
Field[] declaredFields = bean.getClass().getDeclaredFields();
boolean cglib = Arrays.stream(declaredFields).anyMatch(x -> x.getName().contains("CGLIB"));
// 如果是cglib 代理找其父类
if(cglib){
declaredFields = bean.getClass().getSuperclass().getDeclaredFields();
}
// 遍历Bean实例所有属性
for (Field field : declaredFields) {
// 判断field是否含有@Value注解
if (field.isAnnotationPresent(Value.class)) {
// 读取Value注解占位符
keyResolver = field.getAnnotation(Value.class).value();
try {
// 读取属性值
valueResolver = propertyResolver.resolveRequiredPlaceholders(keyResolver);
// EL表达式解析
// 兼容形如:@Value("#{'${codest.five.url}'.split(',')}")含有EL表达式的情况
Expression expression = spelExpressionParser.parseExpression(valueResolver, templateParserContext);
if(field.getType() == Boolean.class){
parserValue =Boolean.valueOf(expression.getValue().toString());
}
else if(field.getType() == Integer.class){
parserValue =Integer.valueOf(expression.getValue().toString());
}
else if(field.getType() == Long.class){
parserValue =Long.valueOf(expression.getValue().toString());
}else {
parserValue = expression.getValue(field.getType());
}
} catch (IllegalArgumentException e) {
logger.warn("{}", e.getMessage());
continue;
}
// 判断配置项是否存在
if (Objects.nonNull(valueResolver)) {
field.setAccessible(true);
try {
field.set(bean, parserValue);
continue;
} catch (IllegalAccessException e) {
logger.error("{}刷新属性值出错, bean: [{}], field: [{}], value: [{}]", bean.getClass().getName(), field.getName(), valueResolver);
}
}
}
}
}
SpringBean 工具类
代码语言:javascript复制
代码语言:javascript复制public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过name获取 Bean.
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
//通过class获取Bean.
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
//通过name,以及Clazz返回指定的Bean
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
测试代码
代码语言:javascript复制@Component
public class Person {
@Value("${person.isopen:false}")
private Boolean isopen;
// 通过反射,必须有get set
public Boolean getIsopen() {
return isopen;
}
public void setIsopen(Boolean isopen) {
this.isopen = isopen;
}
}
@Autowired
private ConfigurablePropertyResolver configurablePropertyResolver;
@Autowired
private ConfigurableEnvironment configurableEnvironment;
@Autowired
private Person person;
/**
* 动态刷新参数接口
* @param map
* @return Map<String, Object>
*/
@PostMapping("private/reSetProperties")
public Map<String, Object> reSetProperties(@RequestBody Map<String, Object> map) {
System.out.println(" 改变之前 " person.getIsopen());
String name = String.valueOf(map.get("beanName"));
map.remove("beanName");
SpringUtils.refreshEnvironment(map,configurableEnvironment);
Object bean = SpringContextUtil.getBean(name);
SpringUtils.refreshBean(bean,configurablePropertyResolver);
System.out.println(" 改变之后 " person.getIsopen());
return Response.customSuccessResponse(" 刷新成功");
}
postman 测试
结果
完美,喜欢,点赞转发