Soul-源码阅读14-Nacos同步数据分析2

问题回顾解决

继续分析昨天boot-strap启动报错NPE的问题,提示:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'nacosSyncDataService' defined in class path resource [org/dromara/soul/springboot/starter/sync/data/nacos/NacosSyncDataConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.dromara.soul.sync.data.api.SyncDataService]: Factory method 'nacosSyncDataService' threw exception; nested exception is com.alipay.sofa.rpc.core.exception.SofaRpcRuntimeException: RPC-010010015: 构造客户端代理出错! 

原因是:soul-bootstrap 启动的时候会去,nacos获取网关数据,通过debugger,拿到的是空数据,使用nacos同步数据的时候,如果网关只代理http服务(无元数据),soul-bootstrap是启动不起来的。

  • 去启动一下sofa服务。然后在soul-admin同步一下元数据。
  • soul-admin 在系统管理-元数据管理, 点击同步数据按钮,将元数据会同步到nacos。
  • 再次启动boot-strap,就提示成功啦。
2021-01-28 22:56:36.092  INFO 14652 --- [           main] d.s.s.s.s.d.n.NacosSyncDataConfiguration : you use nacos sync soul data.......
2021-01-28 22:56:37.318  INFO 14652 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2021-01-28 22:56:39.379  INFO 14652 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 9195
2021-01-28 22:56:39.394  INFO 14652 --- [           main] o.d.s.b.SoulBootstrapApplication         : Started SoulBootstrapApplication in 10.686 seconds (JVM running for 16.254)

Soul-源码阅读14-Nacos同步数据分析2_第1张图片

小结:soul-bootstrap 启动不起来报空指针异常,首先soul-admin启动后不会主动向nacos同步网关数据,需要手动同步,这个问题困扰了挺长时间,最后是看了其他同学的分享,才恍然大悟。

源码分析

  • 数据初始化更新的时候 NacosCacheHandler,通过调用 watcherData 方法,使用Nacos提供的 Listener 来注册当Nacos发布配置时候,可以监听到事件。

    public class NacosCacheHandler {
    。。。。。。
        protected void watcherData(final String dataId, final OnChange oc) {
            Listener listener = new Listener() {
                @Override
                public void receiveConfigInfo(final String configInfo) {
                    oc.change(configInfo);
                }
    
                @Override
                public Executor getExecutor() {
                    return null;
                }
            };
            oc.change(getConfigAndSignListener(dataId, listener));
            LISTENERS.computeIfAbsent(dataId, key -> new ArrayList<>()).add(listener);
        }
    
  • soul-admin的Nacos配置类 NacosConfiguration#nacosConfigService 初始化bean时通过 NacosFactory 创建配置服务。 DataChangedEventDispatcher 负责调用具体的监听实现类对 DataChangedEvent事件进行处理,实现类NacosDataChangedListener 监听器会监听配置的变化,NacosDataChangedListener 会执行 onRuleChanged,updateRuleMap 先将网关数据同步至内存,在通过publishConfig同步至nacos。

    public ConfigService nacosConfigService(final NacosProperties nacosProp) throws Exception {
        Properties properties = new Properties();
        if (nacosProp.getAcm() != null && nacosProp.getAcm().isEnabled()) {
            // Use aliyun ACM service
            properties.put(PropertyKeyConst.ENDPOINT, nacosProp.getAcm().getEndpoint());
            properties.put(PropertyKeyConst.NAMESPACE, nacosProp.getAcm().getNamespace());
            // Use subaccount ACM administrative authority
            properties.put(PropertyKeyConst.ACCESS_KEY, nacosProp.getAcm().getAccessKey());
            properties.put(PropertyKeyConst.SECRET_KEY, nacosProp.getAcm().getSecretKey());
        } else {
            properties.put(PropertyKeyConst.SERVER_ADDR, nacosProp.getUrl());
            properties.put(PropertyKeyConst.NAMESPACE, nacosProp.getNamespace());
        }
        return NacosFactory.createConfigService(properties);
    }
    
    public void onSelectorChanged(final List changed, final DataEventTypeEnum eventType) {
        updateSelectorMap(getConfig(NacosPathConstants.SELECTOR_DATA_ID));
        .。。。
        publishConfig(NacosPathConstants.SELECTOR_DATA_ID, SELECTOR_MAP);
    }
    
  • soul-bootstrap 添加了nacos依赖soul-spring-boot-starter-sync-data-nacos ,启动时自动注入类 NacosSyncDataConfiguration 在初始化bean是创建了 NacosSyncDataService 用于监听配置数据的变化并进行同步。

    public SyncDataService nacosSyncDataService(final ObjectProvider configService, final ObjectProvider pluginSubscriber,
                                           final ObjectProvider> metaSubscribers, final ObjectProvider> authSubscribers) {
        log.info("you use nacos sync soul data.......");
        return new NacosSyncDataService(configService.getIfAvailable(), pluginSubscriber.getIfAvailable(),
                metaSubscribers.getIfAvailable(Collections::emptyList), authSubscribers.getIfAvailable(Collections::emptyList));
    }
    

总结:

数据同步原理目前看都是类似的,下一章计划深入分析 admin 和 bootstrap的整个过程,验证下。

你可能感兴趣的:(Soul,Nacos,java,网关)