NacosValue 註解

NacosValue 定義在 nacos-api 工程中:com.alibaba.nacos.api.config.annotation.NacosValueweb

 

註解解析在 nacos-spring-project 工程中:spring

com.alibaba.nacos.spring.util.NacosBeanUtils#registerNacosValueAnnotationBeanPostProcessorapi

com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessorapp

實現 BeanPostProcessor 接口,能夠在建立 bean 的過程當中插入自定義邏輯,NacosValueAnnotationBeanPostProcessor 掃描屬性和方法上的 NacosValue 註解。webapp

執行順序: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 拉取更新,若是有更新,則經過事件把新值注入到屬性中。ide

com.alibaba.nacos.client.config.impl.ClientWorker.LongPullingRunnable
com.alibaba.nacos.client.config.impl.CacheData#safeNotifyListener
檢測到變化post

 

 

// 配置文件發生變化,把這種變化轉化爲 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);
}

發佈事件spa

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<NacosConfigReceivedEvent> 接口,NacosConfigReceivedEvent 繼承自 ApplicationEvent。

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);
                }
            }
        }
    }
}
相關文章
相關標籤/搜索