博客
关于我
nacos配置自动刷新源码解析
阅读量:796 次
发布时间:2023-02-14

本文共 8276 字,大约阅读时间需要 27 分钟。

Nacos????????????

????

????Nacos?????Spring Cloud Native???????????????????????????????????????????????????????????????????????????????????????????????????????????????????

??????

1???????????????

???Nacos?????????????????????

[INFO] [server-push] config changed. dataId=..., group=..., tenant=...

????????????????????????????????????ClientWorker???????

public ClientWorker(final ConfigFilterChainManager configFilterChainManager, ServerListManager serverListManager, final NacosClientProperties properties) throws NacosException {    this.configFilterChainManager = configFilterChainManager;    init(properties);    agent = new ConfigRpcTransportClient(properties, serverListManager);    int count = ThreadUtils.getSuitableThreadCount(THREAD_MULTIPLE);    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(Math.max(count, MIN_THREAD_NUM), r -> {        Thread t = new Thread(r);        t.setName("com.alibaba.nacos.client.Worker");        t.setDaemon(true);        return t;    });    agent.setExecutor(executorService);    agent.start();}

?????????ConfigRpcTransportClient???????ScheduledExecutorService????????start()??????????????5???executeConfigListen()?

2?????????

executeConfigListen()?????????????

public void executeConfigListen() {    // ???????????????    Map
> listenCachesMap = new HashMap(16); Map
> removeListenCachesMap = new HashMap(16); // ??????? long now = System.currentTimeMillis(); // ?????????????? boolean needAllSync = now - lastAllSyncTime >= ALL_SYNC_INTERNAL; // 5?? for (CacheData cache : cacheMap.get().values()) { synchronized (cache) { if (cache.isSyncWithServer()) { cache.checkListenerMd5(); if (!needAllSync) { continue; } } if (!cache.isDiscard()) { // ????? if (!cache.isUseLocalConfigInfo()) { List
cacheDatas = listenCachesMap.get(String.valueOf(cache.getTaskId())); if (cacheDatas == null) { cacheDatas = new LinkedList<>(); listenCachesMap.put(String.valueOf(cache.getTaskId()), cacheDatas); } cacheDatas.add(cache); } } else if (cache.isDiscard()) { // ???? if (!cache.isUseLocalConfigInfo()) { List
cacheDatas = removeListenCachesMap.get(String.valueOf(cache.getTaskId())); if (cacheDatas == null) { cacheDatas = new LinkedList<>(); removeListenCachesMap.put(String.valueOf(cache.getTaskId()), cacheDatas); } cacheDatas.add(cache); } } } } // ????????? if (!listenCachesMap.isEmpty()) { for (Map.Entry
> entry : listenCachesMap.entrySet()) { String taskId = entry.getKey(); List
listenCaches = entry.getValue(); // ???????? Map
timestampMap = new HashMap(listenCachesMap.size() * 2); for (CacheData cacheData : listenCaches) { timestampMap.put(GroupKey.getKeyTenant(cacheData.dataId, cacheData.group, cacheData.tenant), cacheData.getLastModifiedTs().longValue()); } // ?????????? ConfigBatchListenRequest configChangeListenRequest = buildConfigRequest(listenCaches); configChangeListenRequest.setListen(true); try { RpcClient rpcClient = ensureRpcClient(taskId); ConfigChangeBatchListenResponse configChangeBatchListenResponse = (ConfigChangeBatchListenResponse) requestProxy(rpcClient, configChangeListenRequest); if (configChangeBatchListenResponse.isSuccess()) { Set
changeKeys = new HashSet(); for (ConfigChangeBatchListenResponse.ConfigContext changeConfig : configChangeBatchListenResponse.getChangedConfigs()) { String changeKey = GroupKey.getKeyTenant(changeConfig.getDataId(), changeConfig.getGroup(), changeConfig.getTenant()); changeKeys.add(changeKey); refreshContentAndCheck(changeKey); } // ????????? for (CacheData cacheData : listenCaches) { String groupKey = GroupKey.getKeyTenant(cacheData.dataId, cacheData.group, cacheData.tenant); if (!changeKeys.contains(groupKey)) { synchronized (cacheData) { if (!cacheData.getListeners().isEmpty()) { Long previousTimestamp = timestampMap.get(groupKey); if (previousTimestamp != null && !cacheData.getLastModifiedTs().compareAndSet(previousTimestamp, System.currentTimeMillis())) { continue; } cacheData.setSyncWithServer(true); } cacheData.setInitializing(false); } } cacheData.setInitializing(false); } } } catch (Exception e) { LOGGER.error("Async listen config change error", e); try { Thread.sleep(50L); } catch (InterruptedException interruptedException) { // ?? } } } } // ?????? if (!removeListenCachesMap.isEmpty()) { for (Map.Entry
> entry : removeListenCachesMap.entrySet()) { String taskId = entry.getKey(); List
removeListenCaches = entry.getValue(); ConfigBatchListenRequest configChangeListenRequest = buildConfigRequest(removeListenCaches); configChangeListenRequest.setListen(false); try { RpcClient rpcClient = ensureRpcClient(taskId); boolean removeSuccess = unListenConfigChange(rpcClient, configChangeListenRequest); if (removeSuccess) { for (CacheData cacheData : removeListenCaches) { synchronized (cacheData) { if (cacheData.isDiscard()) { removeCache(cacheData.dataId, cacheData.group, cacheData.tenant); } } } } } catch (Exception e) { LOGGER.error("Async remove listen config change error", e); } try { Thread.sleep(50L); } catch (InterruptedException interruptedException) { // ?? } } } if (needAllSync) { lastAllSyncTime = now; } if (hasChangedKeys) { notifyListenConfig(); }}

3????????

?initRpcClientHandler??????????????????????Handler?

private void initRpcClientHandler(final RpcClient rpcClientInner) {    rpcClientInner.registerServerRequestHandler((request) -> {        if (request instanceof ConfigChangeNotifyRequest) {            ConfigChangeNotifyRequest configChangeNotifyRequest = (ConfigChangeNotifyRequest) request;            LOGGER.info("[{}] [server-push] config changed. dataId={}, group={}, tenant={}",                     rpcClientInner.getName(), configChangeNotifyRequest.getDataId(),                     configChangeNotifyRequest.getGroup(), configChangeNotifyRequest.getTenant());            String groupKey = GroupKey.getKeyTenant(configChangeNotifyRequest.getDataId(),                     configChangeNotifyRequest.getGroup(), configChangeNotifyRequest.getTenant());            CacheData cacheData = cacheMap.get().get(groupKey);            if (cacheData != null) {                synchronized (cacheData) {                    cacheData.getLastModifiedTs().set(System.currentTimeMillis());                    cacheData.setSyncWithServer(false);                    notifyListenConfig();                }            }            return new ConfigChangeNotifyResponse();        }        return null;    });    // ????????}

??????????????Handler????????????????notifyListenConfig()???????????????

??@ConfigurationProperties???bean????

1???????

?refreshEnvironment()??????????????????????????????

public synchronized Set
refreshEnvironment() { Map
before = extract(this.context.getEnvironment().getPropertySources()); updateEnvironment(); Set
keys = changes(before, extract(this.context.getEnvironment().getPropertySources())).keySet(); this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys)); return keys;}

??????????ConfigurationPropertiesRebinder????????rebind()?????bean????????????

2?@RefreshScope???bean????

@RefreshScope???bean??refreshAll()???????

@ManagedOperation(description = "Dispose of the current instance of all beans in this scope and force a refresh on next method execution.")public void refreshAll() {    super.destroy();    this.context.publishEvent(new RefreshScopeRefreshedEvent());}

??GenericScope?destroy()??????????????bean????????

????

Nacos?????????????????

  • ?????????ConfigRpcTransportClient????????
  • ?????????5???executeConfigListen()????????
  • ????????????????????????????
  • ?????????@ConfigurationProperties?@RefreshScope?????bean??????
  • ????????????????????????????Nacos?????????????

    转载地址:http://gwcfk.baihongyu.com/

    你可能感兴趣的文章
    MySQL配置信息解读(my.cnf)
    查看>>
    Mysql配置文件my.ini详解
    查看>>
    MySQL配置文件深度解析:10个关键参数及优化技巧---强烈要求的福利来咯。
    查看>>
    Mysql配置表名忽略大小写(SpringBoot连接表时提示不存在,实际是存在的)
    查看>>
    MySQL里的那些日志们
    查看>>
    MySQL锁
    查看>>
    MySQL锁与脏读、不可重复读、幻读详解
    查看>>
    mysql锁机制,主从复制
    查看>>
    Mysql锁机制,行锁表锁
    查看>>
    Mysql锁(2):表级锁
    查看>>
    MySQL错误提示mysql Statement violates GTID consistency
    查看>>
    MySQL集群解决方案(4):负载均衡
    查看>>
    MySQL面试宝典
    查看>>
    mysql面试题学校三表查询_mysql三表查询分组后取每组最大值,mysql面试题。
    查看>>
    Mysql面试题精选
    查看>>
    MySQL面试题集锦
    查看>>
    mysql面试题,存储引擎InnoDB和MyISAM
    查看>>
    mysql面试题:为什么MySQL单表不能超过2000W条数据?
    查看>>
    mysql面试题:创建索引时会不会锁表?
    查看>>
    mysql面试题:高度为3的B+树可以存放多少数据?
    查看>>