Nacos配置的自动刷新

 Nacos文件需要自动刷新时,整合SpringCloud使用@RefreshScope注解https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html,其通过com.alibaba.cloud.nacos.NacosConfigAutoConfiguration完成相关类的自动注入;只使用SpringBoot时使用@NacosValue(autoRefreshed = true)注解,默认autoRefreshed 为false,不刷新https://nacos.io/zh-cn/docs/quick-start-spring-boot.html,其通过com.alibaba.boot.nacos.config.autoconfigure.NacosConfigAutoConfiguration(@EnableNacosConfig),完成相关类的自动注入;以整合SpringBoot为例。

NacosConfigService的初始化是在NacosConfigManager构造函数中完成的,其通过NacosConfigProperties (bootstrap文件中的spring.cloud.nacos.config)配置的相关信息进行实例化。NacosConfigService中构建了ClientWorker客户端,定时更新配置文件。

public NacosConfigManager(NacosConfigProperties nacosConfigProperties) {
    this.nacosConfigProperties = nacosConfigProperties;
    createConfigService(nacosConfigProperties);
}

static ConfigService createConfigService(NacosConfigProperties nacosConfigProperties) {
    if(Objects.isNull(service)) {
        Class var1 = NacosConfigManager.class;
        synchronized(NacosConfigManager.class) {
            try {
                if(Objects.isNull(service)) {
                    service = NacosFactory.createConfigService(nacosConfigProperties.assembleConfigServiceProperties());
                }
            } catch (NacosException var4) {
            }
        }
    }
    return service;
}
public NacosConfigService(Properties properties) throws NacosException {
    String encodeTmp = properties.getProperty("encode");
    if(StringUtils.isBlank(encodeTmp)) {
        this.encode = "UTF-8";
    } else {
        this.encode = encodeTmp.trim();
    }
    this.initNamespace(properties);
    //生成对Nacos服务端http请求的代理类
    this.agent = new MetricsHttpAgent(new ServerHttpAgent(properties));
    this.agent.start();
    //构建ClientWorker客户端,实时更新配置文件
    this.worker = new ClientWorker(this.agent, this.configFilterChainManager, properties);
}
public ClientWorker(final HttpAgent agent, ConfigFilterChainManager configFilterChainManager, Properties properties) {
    this.agent = agent;
    this.configFilterChainManager = configFilterChainManager;
    this.init(properties);
    this.executor = Executors.newScheduledThreadPool(1, new ThreadFactory() {
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setName("com.alibaba.nacos.client.Worker." + agent.getName());
            t.setDaemon(true);
            return t;
        }
    });
    this.executorService = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() {
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setName("com.alibaba.nacos.client.Worker.longPolling." + agent.getName());
            t.setDaemon(true);
            return t;
        }
    });
    //定时检测远端配置是否发生改变,
    this.executor.scheduleWithFixedDelay(new Runnable() {
        public void run() {
            try {
                ClientWorker.this.checkConfigInfo();
            } catch (Throwable var2) {
                ClientWorker.LOGGER.error("[" + agent.getName() + "] [sub-check] rotate check error", var2);
            }
        }
    }, 1L, 10L, TimeUnit.MILLISECONDS);
}

ClientWorker.checkConfigInfo

public void checkConfigInfo() {
    //监听的文件的个数
    int listenerSize = ((Map)this.cacheMap.get()).size();
    //监听的文件的个数/设置的单次请求处理的个数=向上取整得到任务个数
    int longingTaskCount = (int)Math.ceil((double)listenerSize / ParamUtil.getPerTaskConfigSize());
    if((double)longingTaskCount > this.currentLongingTaskCount) {
        for(int i = (int)this.currentLongingTaskCount; i < longingTaskCount; ++i) {
            this.executorService.execute(new ClientWorker.LongPollingRunnable(i));
        }
        this.currentLongingTaskCount = (double)longingTaskCount;
    }

}
class LongPollingRunnable implements Runnable {
    private int taskId;
    public LongPollingRunnable(int taskId) {
        this.taskId = taskId;
    }
    public void run() {
        ArrayList cacheDatas = new ArrayList();
        ArrayList inInitializingCacheList = new ArrayList();
        try {
            Iterator e = ((Map)ClientWorker.this.cacheMap.get()).values().iterator();
            while(e.hasNext()) {
                CacheData cacheData = (CacheData)e.next();
                if(cacheData.getTaskId() == this.taskId) {
                    cacheDatas.add(cacheData);
                    try {
                        //检查本地的配置文件数据和缓存中的最新数据是否一致,判断配置文件数据是否变化
                        ClientWorker.this.checkLocalConfig(cacheData);
                        if(cacheData.isUseLocalConfigInfo()) {//已经变化
                            //检查文件的文件是否改变,如果改变,通知监听了这个配置文件的监听器
                            cacheData.checkListenerMd5();
                        }
                    } 
                }
            }
            //向Nacos服务发送请求,检查cacheDatas中的配置文件哪些发生了变化
            List e1 = ClientWorker.this.checkUpdateDataIds(cacheDatas, inInitializingCacheList);
            ClientWorker.LOGGER.info("get changedGroupKeys:" + e1);
            Iterator cacheData2 = e1.iterator();
            //遍历发生变化的cacheData
            while(cacheData2.hasNext()) {
                String cacheData1 = (String)cacheData2.next();
                String[] key = GroupKey.parseKey(cacheData1);
                String dataId = key[0];
                String group = key[1];
                String tenant = null;
                if(key.length == 3) {
                    tenant = key[2];
                }
                try {
                    //发送请求,获取最新的配置信息
                    String[] ioe = ClientWorker.this.getServerConfig(dataId, group, tenant, 3000L);
                    CacheData message1 = (CacheData)((Map)ClientWorker.this.cacheMap.get()).get(GroupKey.getKeyTenant(dataId, group, tenant));
                    //更新缓存中CacheData 的content内容及MD5值
                    message1.setContent(ioe[0]);
                    if(null != ioe[1]) {
                        message1.setType(ioe[1]);
                    }
                }
            }
        } catch (Throwable var14) {
            ClientWorker.this.executorService.schedule(this, (long)ClientWorker.this.taskPenaltyTime, TimeUnit.MILLISECONDS);
        }
    }
}
List<String> checkUpdateDataIds(List<CacheData> cacheDatas, List<String> inInitializingCacheList) throws IOException {
    StringBuilder sb = new StringBuilder();
    Iterator isInitializingCacheList = cacheDatas.iterator();
    while(isInitializingCacheList.hasNext()) {
        CacheData cacheData = (CacheData)isInitializingCacheList.next();
        //使用间隔符拼接请求cacheData的dataId、group、Md5的值作为参数,服务端获取对应的文件后,比对MD5值,判断文件是否发生改变
        //extension-config.propertiesDEFAULT_GROUPnacos-demo.yamlDEFAULT_GROUPshared-config
        if(!cacheData.isUseLocalConfigInfo()) {
            sb.append(cacheData.dataId).append(Constants.WORD_SEPARATOR);
            sb.append(cacheData.group).append(Constants.WORD_SEPARATOR);
            if(StringUtils.isBlank(cacheData.tenant)) {
                sb.append(cacheData.getMd5()).append(Constants.LINE_SEPARATOR);
            } else {
                sb.append(cacheData.getMd5()).append(Constants.WORD_SEPARATOR);
                sb.append(cacheData.getTenant()).append(Constants.LINE_SEPARATOR);
            }
            if(cacheData.isInitializing()) {
                inInitializingCacheList.add(GroupKey.getKeyTenant(cacheData.dataId, cacheData.group, cacheData.tenant));
            }
        }
    }
    boolean isInitializingCacheList1 = !inInitializingCacheList.isEmpty();
    return this.checkUpdateConfigStr(sb.toString(), isInitializingCacheList1);
}
CacheData.checkListenerMd5方法,用于通过比对MD5,判断监听器中保存的配置和最新的配置文件是不是相同,如果发生改变,回调对应的监听器
void checkListenerMd5() {
    Iterator var1 = this.listeners.iterator();

    while(var1.hasNext()) {
        ManagerListenerWrap wrap = (ManagerListenerWrap)var1.next();
        if(!this.md5.equals(wrap.lastCallMd5)) {
            this.safeNotifyListener(this.dataId, this.group, this.content, this.type, this.md5, wrap);
        }
    }

}

 CacheData.safeNotifyListener

private void safeNotifyListener(final String dataId, final String group, final String content, final String type, final String md5, final ManagerListenerWrap listenerWrap) {
    final Listener listener = listenerWrap.listener;
    Runnable job = new Runnable() {
        public void run() {
            ClassLoader myClassLoader = Thread.currentThread().getContextClassLoader();
            ClassLoader appClassLoader = listener.getClass().getClassLoader();
            try {
                if(listener instanceof AbstractSharedListener) {
                    AbstractSharedListener t = (AbstractSharedListener)listener;
                    t.fillContext(dataId, group);
                }
                Thread.currentThread().setContextClassLoader(appClassLoader);
                ConfigResponse t1 = new ConfigResponse();
                t1.setDataId(dataId);
                t1.setGroup(group);
                t1.setContent(content);
                CacheData.this.configFilterChainManager.doFilter((IConfigRequest)null, t1);
                String contentTmp = t1.getContent();
                //更新environment中的配置文件,listener的创建是在NacosPropertySourcePostProcessor.addListenerIfAutoRefreshed中完成的
                listener.receiveConfigInfo(contentTmp);
                if(listener instanceof AbstractConfigChangeListener) {
                    Map data = ConfigChangeHandler.getInstance().parseChangeData(listenerWrap.lastContent, content, type);
                    ConfigChangeEvent event = new ConfigChangeEvent(data);
                    ((AbstractConfigChangeListener)listener).receiveConfigChange(event);
                    listenerWrap.lastContent = content;
                }

                listenerWrap.lastCallMd5 = md5;
            } catch (NacosException var11) {
            } catch (Throwable var12) {
            } finally {
            }
        }
    };
    long startNotify = System.currentTimeMillis();
    try {
        if(null != listener.getExecutor()) {
            listener.getExecutor().execute(job);
        } else {
            job.run();
        }
    } catch (Throwable var13) {
    }
    long finishNotify = System.currentTimeMillis();
}
DelegatingEventPublishingListener.receiveConfigInfo
public void receiveConfigInfo(String content) {
    //替换environment中的propertySources的配置
    this.onReceived(content);
    //发送NacosConfigReceivedEvent事件,通知监听器
    this.publishEvent(content);
}
NacosPropertySourcePostProcessor.addListenerIfAutoRefreshed,为ConfigService增加一个listener,当配置改变时回调listener的receiveConfigInfo更新environment中propertySources的文件
public static void addListenerIfAutoRefreshed(final NacosPropertySource nacosPropertySource, Properties properties, final ConfigurableEnvironment environment) {
    if(nacosPropertySource.isAutoRefreshed()) {
        final String dataId = nacosPropertySource.getDataId();
        final String groupId = nacosPropertySource.getGroupId();
        final String type = nacosPropertySource.getType();
        NacosServiceFactory nacosServiceFactory = NacosBeanUtils.getNacosServiceFactoryBean(beanFactory);
        try {
            ConfigService e = nacosServiceFactory.createConfigService(properties);
            AbstractListener listener = new AbstractListener() {
                public void receiveConfigInfo(String config) {
                    String name = nacosPropertySource.getName();
                    NacosPropertySource newNacosPropertySource = new NacosPropertySource(dataId, groupId, name, config, type);
                    newNacosPropertySource.copy(nacosPropertySource);
                    MutablePropertySources propertySources = environment.getPropertySources();
                    propertySources.replace(name, newNacosPropertySource);
                }
            };
            if(e instanceof EventPublishingConfigService) {
                ((EventPublishingConfigService)e).addListener(dataId, groupId, type, listener);
            } else {
                e.addListener(dataId, groupId, listener);
            }
        } catch (NacosException var9) {
            throw new RuntimeException("ConfigService can\'t add Listener with properties : " + properties, var9);
        }
    }
}
NacosValueAnnotationBeanPostProcessor.onApplicationEvent从event中获取最新的配置信息,转化为configProperties,通过配置的key从placeholderNacosValueTargetMap中获取需要更新配置文件的实例,并更新对应的属性值。
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);
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_33513289/article/details/114970499