zoukankan      html  css  js  c++  java
  • NacosValue 注解

    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<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);
                    }
                }
            }
        }
    }
  • 相关阅读:
    Python 操作 Azure Blob Storage
    @private、@protected与@public三者之间的区别
    iOS设计模式
    NSMapTable、NSHashTable与NSPointerArray的封装
    iOS设计模式
    用UITextView加载rtfd文件
    UIWebView如何加载本地图片
    [翻译] BezierString
    [翻译] AYVibrantButton
    用NSOperation写下载队列
  • 原文地址:https://www.cnblogs.com/allenwas3/p/11003865.html
Copyright © 2011-2022 走看看