大体思路是nacos 本地有一个定时任务(使用定时任务线程池实现),然后进行扫描,比较文件之前和之后的MD5 值,假如md5 值发生了变化,则进行前后文件的比较 

首先通过类 “NacosContextRefresher”

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        // many Spring context
        if (this.ready.compareAndSet(false, true)) {
            this.registerNacosListenersForApplications();
        }
    }

然后到 registerNacosListenersForApplications 方法

复制代码
    private void registerNacosListenersForApplications() {
        if (isRefreshEnabled()) {
            for (NacosPropertySource propertySource : NacosPropertySourceRepository
                    .getAll()) {
                if (!propertySource.isRefreshable()) {
                    continue;
                }
                String dataId = propertySource.getDataId();
                registerNacosListener(propertySource.getGroup(), dataId);
                log.info("listening config: dataId={}, group={}", dataId, propertySource.getGroup());
            }
        }
    }
复制代码

再到

复制代码
private void registerNacosListener(final String groupKey, final String dataKey) {
        String key = NacosPropertySourceRepository.getMapKey(dataKey, groupKey);
        Listener listener = listenerMap.computeIfAbsent(key,
                lst -> new AbstractSharedListener() {
                    @Override
                    public void innerReceive(String dataId, String group,
                            String configInfo) {
                        refreshCountIncrement();
                        nacosRefreshHistory.addRefreshRecord(dataId, group, configInfo);
                        // todo feature: support single refresh for listening
                        applicationContext.publishEvent(
                                new RefreshEvent(this, null, "Refresh Nacos config"));
                        if (log.isDebugEnabled()) {
                            log.debug(String.format(
                                    "Refresh Nacos config group=%s,dataId=%s,configInfo=%s",
                                    group, dataId, configInfo));
                        }
                    }
                });
        try {
            configService.addListener(dataKey, groupKey, listener);
        }
        catch (NacosException e) {
            log.warn(String.format(
                    "register fail for nacos listener ,dataId=[%s],group=[%s]", dataKey,
                    groupKey), e);
        }
    }
复制代码

其中重点关注 “applicationContext.publishEvent( new RefreshEvent(this, null, "Refresh Nacos config")); ”

这段代码,主要是发布事件,然后进入到类“AbstractApplicationContext” 中的

public void publishEvent(ApplicationEvent event) {
        publishEvent(event, null);
    }

再次进入到方法

复制代码
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");

        // Decorate event as an ApplicationEvent if necessary
        ApplicationEvent applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent) event;
        }
        else {
            applicationEvent = new PayloadApplicationEvent<>(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
            }
        }

        // Multicast right now if possible - or lazily once the multicaster is initialized
        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        }
        else {
            getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
        }

        // Publish event via parent context as well...
        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
            }
            else {
                this.parent.publishEvent(event);
            }
        }
    }
复制代码

再次进入到从“getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);”方法进入到

类“SimpleApplicationEventMulticaster”的方法

复制代码
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        Executor executor = getTaskExecutor();
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                invokeListener(listener, event);
            }
        }
    }
复制代码

然后走入到分支方法: invokeListener(listener, event); 再然后进入到方法

复制代码
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
        if (errorHandler != null) {
            try {
                doInvokeListener(listener, event);
            }
            catch (Throwable err) {
                errorHandler.handleError(err);
            }
        }
        else {
            doInvokeListener(listener, event);
        }
    }
复制代码

在走入到分支:doInvokeListener(listener, event); 中再走入到方法

复制代码
@SuppressWarnings({"rawtypes", "unchecked"})
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
                    (event instanceof PayloadApplicationEvent &&
                            matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                // -> let's suppress the exception.
                Log loggerToUse = this.lazyLogger;
                if (loggerToUse == null) {
                    loggerToUse = LogFactory.getLog(getClass());
                    this.lazyLogger = loggerToUse;
                }
                if (loggerToUse.isTraceEnabled()) {
                    loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }
复制代码

走入到方法 listener.onApplicationEvent(event); 最后跳入到 类“RefreshEventListener”的方法:

复制代码
@Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationReadyEvent) {
            handle((ApplicationReadyEvent) event);
        }
        else if (event instanceof RefreshEvent) {
            handle((RefreshEvent) event);
        }
    }
复制代码

从分支 handle((RefreshEvent) event); 再跳入到

    public void handle(RefreshEvent event) {
        if (this.ready.get()) { // don't handle events before app is ready
            log.debug("Event received " + event.getEventDesc());
            Set<String> keys = this.refresh.refresh();
            log.info("Refresh keys changed: " + keys);
        }
    }

这里我们需要重点关注 this.refresh 的 refresh()方法,先是进入到类 “ContextRefresher”的方法:

public synchronized Set<String> refresh() {
        Set<String> keys = refreshEnvironment();
        this.scope.refreshAll();
        return keys;
    }

然后重点来看 “refreshEnvironment” 方法

复制代码
    public synchronized Set<String> refreshEnvironment() {
        //这里的before 主要获取的是文件修改前的值
        Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources());
        // 刷新配置文件
        updateEnvironment();
        // 进行更新前后差异比较
        Set<String> keys = changes(before, extract(this.context.getEnvironment().getPropertySources())).keySet();
        // 重复一遍上面的时间发布机制
        this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
        return keys;
    }
复制代码