nacos自定义@Value注解动态配置解析器

文章目录

前言

紧接上文,nacos-spring-boot版本不支持@Value注解的属性的动态更改,那么我们可以依赖nacos提供的一些扩展机制,自己来实现这个功能

实现

直接利用nacos配置更改时会发布的事件NacosConfigReceivedEvent,扩展一个监听该事件的监听器即可


package com.alibaba.nacos.example.spring.boot.controller;

import com.alibaba.nacos.spring.context.event.config.NacosConfigReceivedEvent;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.*;


/**
 * @value注解动态更新监听器
 */
@Component
public class ValueAnnotationApplicationListener implements BeanFactoryAware,
        ApplicationListener<NacosConfigReceivedEvent> {

    private ConfigurableListableBeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
    }

    /**
     * 判断字段是否有@Value注解
     *
     * @param ao
     * @return
     */
    private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
        MergedAnnotations annotations = MergedAnnotations.from(ao);
        MergedAnnotation<?> annotation = annotations.get(Value.class);
        if (annotation.isPresent()) {
            return annotation;
        }
        return null;
    }

    @Override
    public void onApplicationEvent(NacosConfigReceivedEvent event) {
        Iterator<String> beanNamesIterator = beanFactory.getBeanNamesIterator();
        // 循环所有的bean
        while (beanNamesIterator.hasNext()) {
            String beanName = beanNamesIterator.next();
            Object bean = beanFactory.getBean(beanName);
            // 取出类本身的属性成员(包括私有、共有、保护)
            Field[] allFields = bean.getClass().getDeclaredFields();
            for (Field field : allFields) {
                // 如果有@Value注解
                MergedAnnotation mergedAnnotation = findAutowiredAnnotation(field);
                if (mergedAnnotation != null) {
                    // 以下代码拷贝自AutowiredAnnotationBeanPostProcessor类
                    DependencyDescriptor desc = new DependencyDescriptor(field, true);
                    desc.setContainingClass(bean.getClass());
                    Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
                    TypeConverter typeConverter = beanFactory.getTypeConverter();
                    // 解析出value值
                    Object value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
                    ReflectionUtils.makeAccessible(field);
                    try {
                        Object oldValue = field.get(bean);
                        if (!Objects.equals(oldValue, value)) {
                            field.set(bean, value);
                        }
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}

让该类可以被spring扫描到即可,以上代码的来源是spring本身对@Value注解的实现类AutowiredAnnotationBeanPostProcessor,同时利用了它内部解析${xxx}的解析器

大概的思路

  1. 就是扫描所有的bean
  2. 判断那些bean里面有需要修改的字段
  3. 重新把这里字段去spring的environment中查询
  4. 如果和当前不一样,那么重新赋值即可

以上代码仅供参考,还有需要优化的地方,比如

  1. 扫描所有bean会不会比较耗时,影响性能
  2. 对方法上的@Value的处理

总结

以上功能可以简单的实现,实现思路比较明确,也可以看下apollo动态配置中心是如何实现这个功能的,可以参考下怎么写比较优雅

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值