美文网首页
SpringBoot集成nacos配置中心源码

SpringBoot集成nacos配置中心源码

作者: hcq0514 | 来源:发表于2021-01-29 11:06 被阅读0次
    nacos config包主要引入了以下几个依赖(初始化组件)
    org.springframework.cloud.bootstrap.BootstrapConfiguration=\
    com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.alibaba.cloud.nacos.NacosConfigAutoConfiguration,\
    com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration
    org.springframework.boot.diagnostics.FailureAnalyzer=\
    com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer
    
    1. NacosConfigBootstrapConfiguration
    public class NacosConfigBootstrapConfiguration {
    
        @Bean
        @ConditionalOnMissingBean
        //初始化application里配置的参数
        public NacosConfigProperties nacosConfigProperties() {
            return new NacosConfigProperties();
        }
    
        @Bean
        @ConditionalOnMissingBean
        //初始化一个NacosConfigManager 
        public NacosConfigManager nacosConfigManager(
                NacosConfigProperties nacosConfigProperties) {
            return new NacosConfigManager(nacosConfigProperties);
        }
    
        @Bean
        //只是初始化一个NacosPropertySourceLocator 
        public NacosPropertySourceLocator nacosPropertySourceLocator(
                NacosConfigManager nacosConfigManager) {
            return new NacosPropertySourceLocator(nacosConfigManager);
        }
    
    }
    
    • nacosConfigProperties方法,主要是对参数进行一些处理
        private void overrideFromEnv() {
            if (StringUtils.isEmpty(this.getServerAddr())) {
                String serverAddr = environment
                        .resolvePlaceholders("${spring.cloud.nacos.config.server-addr:}");
                if (StringUtils.isEmpty(serverAddr)) {
                    serverAddr = environment.resolvePlaceholders(
                            "${spring.cloud.nacos.server-addr:localhost:8848}");
                }
                this.setServerAddr(serverAddr);
            }
            if (StringUtils.isEmpty(this.getUsername())) {
                this.setUsername(
                        environment.resolvePlaceholders("${spring.cloud.nacos.username:}"));
            }
            if (StringUtils.isEmpty(this.getPassword())) {
                this.setPassword(
                        environment.resolvePlaceholders("${spring.cloud.nacos.password:}"));
            }
        }
    
    • nacosConfigManager方法,主要是创建一个nacosConfigManager
        static ConfigService createConfigService(
                NacosConfigProperties nacosConfigProperties) {
            if (Objects.isNull(service)) {
                synchronized (NacosConfigManager.class) {
                    try {
                        if (Objects.isNull(service)) {
                            service = NacosFactory.createConfigService(
                                    nacosConfigProperties.assembleConfigServiceProperties());
                        }
                    }
                    catch (NacosException e) {
                        log.error(e.getMessage());
                        throw new NacosConnectionFailureException(
                                nacosConfigProperties.getServerAddr(), e.getMessage(), e);
                    }
                }
            }
            return service;
        }
    这边主要调用
    com.alibaba.nacos.client.config.NacosConfigService#NacosConfigService方法来(后面详解)
    
    • NacosPropertySourceLocator主要是创建一个NacosPropertySourceLocator
        public NacosPropertySourceLocator(NacosConfigManager nacosConfigManager) {
            this.nacosConfigManager = nacosConfigManager;
            this.nacosConfigProperties = nacosConfigManager.getNacosConfigProperties();
        }
    
    注册listener
        @Override
        public void onApplicationEvent(ApplicationReadyEvent event) {
            // many Spring context
            if (this.ready.compareAndSet(false, true)) {
                this.registerNacosListenersForApplications();
            }
        }
    
        /**
         * register Nacos Listeners.
         */
        private void registerNacosListenersForApplications() {
            if (isRefreshEnabled()) {
                for (NacosPropertySource propertySource : NacosPropertySourceRepository
                        .getAll()) {
                    if (!propertySource.isRefreshable()) {
                        continue;
                    }
                    String dataId = propertySource.getDataId();
                    registerNacosListener(propertySource.getGroup(), dataId);
                }
            }
        }
    

    当获取配置的时候主要是通过NacosPropertySourceLocator#locate来获取(参考spring的配置规则)

        @Override
        public PropertySource<?> locate(Environment env) {
            //env里面主要是springboot的环境配置,包含本地配置active-profile等
            nacosConfigProperties.setEnvironment(env);
            //获取nacos-config配置
            ConfigService configService = nacosConfigManager.getConfigService();
            if (null == configService) {
                log.warn("no instance of config service found, can't load config from nacos");
                return null;
            }
            //获取配置的超时时间
            long timeout = nacosConfigProperties.getTimeout();
            nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService,
                    timeout);
            String name = nacosConfigProperties.getName();
            String dataIdPrefix = nacosConfigProperties.getPrefix();
            if (StringUtils.isEmpty(dataIdPrefix)) {
                dataIdPrefix = name;
            }
            if (StringUtils.isEmpty(dataIdPrefix)) {
                dataIdPrefix = env.getProperty("spring.application.name");
            }
            CompositePropertySource composite = new CompositePropertySource(
                    NACOS_PROPERTY_SOURCE_NAME);
            //加载共享的配置
            loadSharedConfiguration(composite);
            //加载扩展的配置
            loadExtConfiguration(composite);
            //加载当前应用的配置
            loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
            return composite;
        }
    

    这里正式开始加载配置,而加载顺序也可以看出,共享配置 ->扩展配置 -> 当前应用配置
    当后面加载有相同配置的时候,直接覆盖之前的配置。共享跟扩展设置值set的方法已经废弃不用了。
    也就是配置的优先级为 当前应用配置>扩展配置->共享配置

    • 加载共享配置(已经@Deprecated废弃掉了)
        private void loadSharedConfiguration(
                CompositePropertySource compositePropertySource) {
            List<NacosConfigProperties.Config> sharedConfigs = nacosConfigProperties
                    .getSharedConfigs();
            if (!CollectionUtils.isEmpty(sharedConfigs)) {
                checkConfiguration(sharedConfigs, "shared-configs");
                loadNacosConfiguration(compositePropertySource, sharedConfigs);
            }
        }
    
    • 加载共享配置(已经@Deprecated废弃掉了)
        private void loadExtConfiguration(CompositePropertySource compositePropertySource) {
            List<NacosConfigProperties.Config> extConfigs = nacosConfigProperties
                    .getExtensionConfigs();
            if (!CollectionUtils.isEmpty(extConfigs)) {
                checkConfiguration(extConfigs, "extension-configs");
                loadNacosConfiguration(compositePropertySource, extConfigs);
            }
        }
    
    • 加载当前应用配置
        private void loadApplicationConfiguration(
                CompositePropertySource compositePropertySource, String dataIdPrefix,
                NacosConfigProperties properties, Environment environment) {
            String fileExtension = properties.getFileExtension();
            String nacosGroup = properties.getGroup();
            // load directly once by default
            // 直接根据spring.cloud.nacos.config.name配置名称去nacos取,
            // 不带后缀(例如:mall-portal-config)
            loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup,
                    fileExtension, true);
            // load with suffix, which have a higher priority than the default
            // 根据配置配置+后缀去取,优先级高于上面默认的(例如:mall-portal-config.yml)
            loadNacosDataIfPresent(compositePropertySource,
                    dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true);
            // Loaded with profile, which have a higher priority than the suffix
            // 根据profile去取(dev,test等),优先级最高(例如:mall-portal-config-dev.yml)
            for (String profile : environment.getActiveProfiles()) {
                String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
                loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
                        fileExtension, true);
            }
        }
    
    • 不管是从哪获取配置都是调用loadNacosDataIfPresent
        private void loadNacosDataIfPresent(final CompositePropertySource composite,
                final String dataId, final String group, String fileExtension,
                boolean isRefreshable) {
            if (null == dataId || dataId.trim().length() < 1) {
                return;
            }
            if (null == group || group.trim().length() < 1) {
                return;
            }
            //获取nacos配置并包装成NacosPropertySource 
            NacosPropertySource propertySource = this.loadNacosPropertySource(dataId, group,
                    fileExtension, isRefreshable);
            this.addFirstPropertySource(composite, propertySource, false);
        }
    //----------------------------------✂------------------------------------------
    
        private NacosPropertySource loadNacosPropertySource(final String dataId,
                final String group, String fileExtension, boolean isRefreshable) {
            if (NacosContextRefresher.getRefreshCount() != 0) {
                if (!isRefreshable) {
                    return NacosPropertySourceRepository.getNacosPropertySource(dataId,
                            group);
                }
            }
            return nacosPropertySourceBuilder.build(dataId, group, fileExtension,
                    isRefreshable);
        }
    //----------------------------------✂------------------------------------------
    
        NacosPropertySource build(String dataId, String group, String fileExtension,
                boolean isRefreshable) {
            //主要是通过这个方法来从nacos服务端获取数据
            Map<String, Object> p = loadNacosData(dataId, group, fileExtension);
            NacosPropertySource nacosPropertySource = new NacosPropertySource(group, dataId,
                    p, new Date(), isRefreshable);
            //更新本地缓存
            NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource);
            return nacosPropertySource;
        }
    //----------------------------------✂------------------------------------------
    
        private Map<String, Object> loadNacosData(String dataId, String group,
                String fileExtension) {
            String data = null;
            try {
                //从service端获取数据
                data = configService.getConfig(dataId, group, timeout);
                if (StringUtils.isEmpty(data)) {
                    log.warn(
                            "Ignore the empty nacos configuration and get it based on dataId[{}] & group[{}]",
                            dataId, group);
                    return EMPTY_MAP;
                }
                if (log.isDebugEnabled()) {
                    log.debug(String.format(
                            "Loading nacos data, dataId: '%s', group: '%s', data: %s", dataId,
                            group, data));
                }
                //将获取的数据转换成map结构
                Map<String, Object> dataMap = NacosDataParserHandler.getInstance()
                        .parseNacosData(data, fileExtension);
                return dataMap == null ? EMPTY_MAP : dataMap;
            }
            catch (NacosException e) {
                log.error("get data from Nacos error,dataId:{}, ", dataId, e);
            }
            catch (Exception e) {
                log.error("parse data from Nacos error,dataId:{},data:{},", dataId, data, e);
            }
            return EMPTY_MAP;
        }
    
    • 至此nacos config拉取配置中心的代码就完成了,下面的更换配置等属于springboot的内容了,具体nacos config如何工作可以查看nacos config源码分析
      Nacos配置中心源码

    相关文章

      网友评论

          本文标题:SpringBoot集成nacos配置中心源码

          本文链接:https://www.haomeiwen.com/subject/zozszktx.html