前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Springboot @Value 单节点动态刷新

Springboot @Value 单节点动态刷新

作者头像
分享干货的你
发布2021-04-23 11:06:01
2.3K0
发布2021-04-23 11:06:01
举报
文章被收录于专栏:分享干货的你分享干货的你

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 测试

结果

完美,喜欢,点赞转发

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 分享干货的你 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档