NacosValue 定义在 nacos-api 工程中:com.alibaba.nacos.api.config.annotation.NacosValue
注解解析在 nacos-spring-project 工程中:
com.alibaba.nacos.spring.util.NacosBeanUtils#registerNacosValueAnnotationBeanPostProcessor
com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor
实现 BeanPostProcessor 接口,可以在创建 bean 的过程中插入自定义逻辑,NacosValueAnnotationBeanPostProcessor 扫描属性和方法上的 NacosValue 注解。
执行顺序:bean 的构造方法,postProcessBeforeInitialization,init,postProcessAfterInitialization
@Override
public Object postProcessBeforeInitialization(Object bean, final String beanName)
    throws BeansException {
    doWithFields(bean, beanName);
    doWithMethods(bean, beanName);
    return super.postProcessBeforeInitialization(bean, beanName);
}
nacos 客户端定时从 nacos server 拉取更新,如果有更新,则通过事件把新值注入到属性中。
com.alibaba.nacos.client.config.impl.ClientWorker.LongPullingRunnable
com.alibaba.nacos.client.config.impl.CacheData#safeNotifyListener
检测到变化
 
// 配置文件发生变化,把这种变化转化为 spring 事件
private void safeNotifyListener(final String dataId, final String group, final String content,
                                final String md5, final ManagerListenerWrap listenerWrap) {
    final Listener listener = listenerWrap.listener;
    // 把逻辑封装成 job,可异步可同步
    Runnable job = new Runnable() {
        public void run() {
            ClassLoader myClassLoader = Thread.currentThread().getContextClassLoader();
            ClassLoader appClassLoader = listener.getClass().getClassLoader();
            try {
                if (listener instanceof AbstractSharedListener) {
                    AbstractSharedListener adapter = (AbstractSharedListener) listener;
                    adapter.fillContext(dataId, group);
                    LOGGER.info("[{}] [notify-context] dataId={}, group={}, md5={}", name, dataId, group, md5);
                }
                // 执行回调之前先将线程classloader设置为具体webapp的classloader,以免回调方法中调用spi接口是出现异常或错用(多应用部署才会有该问题)。
                Thread.currentThread().setContextClassLoader(appClassLoader);
                ConfigResponse cr = new ConfigResponse();
                cr.setDataId(dataId);
                cr.setGroup(group);
                cr.setContent(content);
                configFilterChainManager.doFilter(null, cr);
                String contentTmp = cr.getContent();
                // 真正发布事件的地方
                listener.receiveConfigInfo(contentTmp);
                listenerWrap.lastCallMd5 = md5;
                LOGGER.info("[{}] [notify-ok] dataId={}, group={}, md5={}, listener={} ", name, dataId, group, md5,
                    listener);
            } catch (NacosException de) {
                LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} errCode={} errMsg={}", name,
                    dataId, group, md5, listener, de.getErrCode(), de.getErrMsg());
            } catch (Throwable t) {
                LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} tx={}", name, dataId, group,
                    md5, listener, t.getCause());
            } finally {
                Thread.currentThread().setContextClassLoader(myClassLoader);
            }
        }
    };
    final long startNotify = System.currentTimeMillis();
    try {
        if (null != listener.getExecutor()) {
            listener.getExecutor().execute(job);
        } else {
            job.run();
        }
    } catch (Throwable t) {
        LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} throwable={}", name, dataId, group,
            md5, listener, t.getCause());
    }
    final long finishNotify = System.currentTimeMillis();
    LOGGER.info("[{}] [notify-listener] time cost={}ms in ClientWorker, dataId={}, group={}, md5={}, listener={} ",
        name, (finishNotify - startNotify), dataId, group, md5, listener);
}
发布事件
com.alibaba.nacos.spring.context.event.config.DelegatingEventPublishingListener#publishEvent
DelegatingEventPublishingListener 类在 nacos-spring-context 工程中
private void publishEvent(String content) {
    NacosConfigReceivedEvent event = new NacosConfigReceivedEvent(configService, dataId, groupId, content);
    applicationEventPublisher.publishEvent(event);
}
消费事件
com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor#onApplicationEvent
NacosValueAnnotationBeanPostProcessor 类在 nacos-spring-context 工程中
NacosValueAnnotationBeanPostProcessor 实现了 ApplicationListener
public void onApplicationEvent(NacosConfigReceivedEvent event) {
    String content = event.getContent();
    if (content != null) {
        Properties configProperties = toProperties(content);
        for (Object key : configProperties.keySet()) {
            String propertyKey = (String)key;
            List<NacosValueTarget> beanPropertyList = placeholderNacosValueTargetMap.get(propertyKey);
            if (beanPropertyList == null) {
                continue;
            }
            String propertyValue = configProperties.getProperty(propertyKey);
            for (NacosValueTarget nacosValueTarget : beanPropertyList) {
                if (nacosValueTarget.method == null) {
                    setField(nacosValueTarget, propertyValue);
                } else {
                    setMethod(nacosValueTarget, propertyValue);
                }
            }
        }
    }
}
 
  
  
  
 
 
  
 
 
 