zoukankan      html  css  js  c++  java
  • Nacos深入浅出(八)

    Nacos-spring-context.java

    感觉这个后台要比之前的Nacos复杂多了,涉及到很多基础的概念,慢慢看,这个后面慢慢更新解析过程

    看到他的目录结构一个是基于注解,一个是XML的解析,之前我们的值基于注解的,我们就看下这个注解的实现过程;

    借助ImportBeanDefinitionRegistrar接口实现bean的动态注入

     https://www.jianshu.com/p/2b993ced6a4c

    NacosBeanDefinitionRegistrar.java
    public class NacosBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware, BeanFactoryAware {
    
        private Environment environment;
    
        private BeanFactory beanFactory;
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            BeanDefinition annotationProcessor = BeanDefinitionBuilder.genericBeanDefinition(
                    PropertySourcesPlaceholderConfigurer.class).getBeanDefinition();
            registry.registerBeanDefinition(PropertySourcesPlaceholderConfigurer.class.getName(), annotationProcessor);
    
            AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                    importingClassMetadata.getAnnotationAttributes(EnableNacos.class.getName()));
    
            // Register Global Nacos Properties Bean
            registerGlobalNacosProperties(attributes, registry, environment, GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
            // Register Nacos Annotation Beans
            registerNacosAnnotationBeans(registry);
            // Invoke NacosPropertySourcePostProcessor immediately
            // in order to enhance the precedence of @NacosPropertySource process
            invokeNacosPropertySourcePostProcessor(beanFactory);
        }
    
        @Override
        public void setEnvironment(Environment environment) {
            this.environment = environment;
        }
    
        public void registerNacosAnnotationBeans(BeanDefinitionRegistry registry) {
            registerNacosCommonBeans(registry);
            registerNacosConfigBeans(registry, environment);
            registerNacosDiscoveryBeans(registry);
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            this.beanFactory = beanFactory;
        }
    }
    NacosConfigBeanDefinitionRegistrar.java
    下面这个操作就是将含有NacosPropertySource注解的类,注册到beanfactory
    public class NacosConfigBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware,
            BeanFactoryAware {
    
        private Environment environment;
    
        private BeanFactory beanFactory;
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AnnotationAttributes attributes = fromMap(metadata.getAnnotationAttributes(EnableNacosConfig.class.getName()));
            // Register Global Nacos Properties Bean
            registerGlobalNacosProperties(attributes, registry, environment, CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
            // Register Nacos Common Beans
            registerNacosCommonBeans(registry);
            // Register Nacos Config Beans
            registerNacosConfigBeans(registry, environment);
            // Invoke NacosPropertySourcePostProcessor immediately
            // in order to enhance the precedence of @NacosPropertySource process
            invokeNacosPropertySourcePostProcessor(beanFactory);
        }
    
        @Override
        public void setEnvironment(Environment environment) {
            this.environment = environment;
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            this.beanFactory = beanFactory;
        }
    }

        invokeNacosPropertySourcePostProcessor(beanFactory);

    NacosBeanUtils.java
     /**
         * Invokes {@link NacosPropertySourcePostProcessor}
         *
         * @param beanFactory {@link BeanFactory}
         */
        public static void invokeNacosPropertySourcePostProcessor(BeanFactory beanFactory) {
            NacosPropertySourcePostProcessor postProcessor =
                    beanFactory.getBean(NacosPropertySourcePostProcessor.BEAN_NAME, NacosPropertySourcePostProcessor.class);
            postProcessor.postProcessBeanFactory((ConfigurableListableBeanFactory) beanFactory);
        }
    NacosPropertySourcePostProcessor.java
     @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            String[] abstractNacosPropertySourceBuilderBeanNames = BeanUtils.getBeanNames(beanFactory,
                AbstractNacosPropertySourceBuilder.class);
    
            this.nacosPropertySourceBuilders = new ArrayList<AbstractNacosPropertySourceBuilder>(
                abstractNacosPropertySourceBuilderBeanNames.length);
    
            for (String beanName : abstractNacosPropertySourceBuilderBeanNames) {
                this.nacosPropertySourceBuilders.add(
                    beanFactory.getBean(beanName, AbstractNacosPropertySourceBuilder.class));
            }
    
            this.configServiceBeanBuilder = getConfigServiceBeanBuilder(beanFactory);
    
            String[] beanNames = beanFactory.getBeanDefinitionNames();
    
            for (String beanName : beanNames) {
                processPropertySource(beanName, beanFactory);
            }
    
        }
     private void processPropertySource(String beanName, ConfigurableListableBeanFactory beanFactory) {
    
            if (processedBeanNames.contains(beanName)) {
                return;
            }
    
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
    
            // Build multiple instance if possible
            List<NacosPropertySource> nacosPropertySources = buildNacosPropertySources(beanName, beanDefinition);
    
            // Add Orderly
            for (NacosPropertySource nacosPropertySource : nacosPropertySources) {
                addNacosPropertySource(nacosPropertySource);
                addListenerIfAutoRefreshed(nacosPropertySource);
            }
    
            processedBeanNames.add(beanName);
        }
    private List<NacosPropertySource> buildNacosPropertySources(String beanName, BeanDefinition beanDefinition) {
            for (AbstractNacosPropertySourceBuilder builder : nacosPropertySourceBuilders) {
                if (builder.supports(beanDefinition)) {
                    return builder.build(beanName, beanDefinition);
                }
            }
            return Collections.emptyList();
        }
     public List<NacosPropertySource> build(String beanName, T beanDefinition) {
            Map<String, Object>[] attributesArray = this.resolveRuntimeAttributesArray(beanDefinition, this.globalNacosProperties);
            int size = attributesArray == null ? 0 : attributesArray.length;
            if (size == 0) {
                return Collections.emptyList();
            } else {
                List<NacosPropertySource> nacosPropertySources = new ArrayList(size);
    
                for(int i = 0; i < size; ++i) {
                    Map<String, Object> attributes = attributesArray[i];
                    if (!CollectionUtils.isEmpty(attributes)) {
                        NacosPropertySource nacosPropertySource = this.doBuild(beanName, beanDefinition, attributesArray[i]);
                        NacosConfigMetadataEvent metadataEvent = this.createMetaEvent(nacosPropertySource, beanDefinition);
                        this.initMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent);
                        this.publishMetadataEvent(metadataEvent);
                        nacosPropertySources.    (nacosPropertySource);
                    }
                }
                return nacosPropertySources;
            }
        }
    protected NacosPropertySource doBuild(String beanName, T beanDefinition, Map<String, Object> runtimeAttributes) {
    
            // Get annotation metadata
            String name = (String) runtimeAttributes.get(NAME_ATTRIBUTE_NAME);
            String dataId = (String) runtimeAttributes.get(DATA_ID_ATTRIBUTE_NAME);
            String groupId = (String) runtimeAttributes.get(GROUP_ID_ATTRIBUTE_NAME);
            Map<String, Object> nacosPropertiesAttributes = (Map<String, Object>) runtimeAttributes.get(PROPERTIES_ATTRIBUTE_NAME);
    
            Properties nacosProperties = resolveProperties(nacosPropertiesAttributes, environment, globalNacosProperties);
    
            String nacosConfig = nacosConfigLoader.load(dataId, groupId, nacosProperties);
    
            if (!StringUtils.hasText(nacosConfig)) {
                if (logger.isWarnEnabled()) {
                    logger.warn(format("There is no content for NacosPropertySource from dataId[%s] , groupId[%s] , properties[%s].",
                            dataId,
                            groupId,
                            valueOf(nacosPropertiesAttributes)));
                }
            }
    
            if (!StringUtils.hasText(name)) {
                name = buildDefaultPropertySourceName(dataId, groupId, nacosProperties);
            }
    
            NacosPropertySource nacosPropertySource = new NacosPropertySource(name, nacosConfig);
    
            nacosPropertySource.setBeanName(beanName);
    
            String beanClassName = beanDefinition.getBeanClassName();
            if (StringUtils.hasText(beanClassName)) {
                nacosPropertySource.setBeanType(resolveClassName(beanClassName, classLoader));
            }
            nacosPropertySource.setGroupId(groupId);
            nacosPropertySource.setDataId(dataId);
            nacosPropertySource.setProperties(nacosProperties);
    
            initNacosPropertySource(nacosPropertySource, beanDefinition, runtimeAttributes);
    
            return nacosPropertySource;
    
        }

    加载初始化的内容

     /**
         * Load Nacos config vid dataId, groupId and {@link Properties acos Properties}
         *
         * @param dataId          dataId
         * @param groupId         groupId
         * @param nacosProperties {@link Properties acos Properties}
         * @return Nacos config
         * @throws RuntimeException If {@link ConfigService} creating is failed.
         */
        public String load(String dataId, String groupId, Properties nacosProperties) throws RuntimeException {
            try {
                configService = nacosServiceFactory != null ?
                        nacosServiceFactory.createConfigService(nacosProperties) :
                        NacosFactory.createConfigService(nacosProperties);
            } catch (NacosException e) {
                throw new RuntimeException("ConfigService can't be created with dataId :"
                        + dataId + " , groupId : " + groupId + " , properties : " + nacosProperties
                        , e);
            }
            return NacosUtils.getContent(configService, dataId, groupId);
        }

     这里我们之前应该是漏掉了,我们会过来再看下,这里根据反射的构造函数决定用哪个构造函数初始化;

    CacheableEventPublishingNacosServiceFactory.java
     public ConfigService createConfigService(Properties properties) throws NacosException {
            Properties copy = new Properties();
            copy.putAll(properties);
            String cacheKey = NacosUtils.identify(copy);
            ConfigService configService = (ConfigService)this.configServicesCache.get(cacheKey);
            if (configService == null) {
                configService = this.doCreateConfigService(copy);
                this.configServicesCache.put(cacheKey, configService);
            }
    
            return configService;
        }
     private ConfigService doCreateConfigService(Properties properties) throws NacosException {
            ConfigService configService = NacosFactory.createConfigService(properties);
            return new EventPublishingConfigService(configService, properties, this.context, this.nacosConfigListenerExecutor);
        }

    不管nacosServiceFactory是否为空,绕到最后都是通过下面的方式进行初始化

    public class ConfigFactory {
        public ConfigFactory() {
        }
    
        public static ConfigService createConfigService(Properties properties) throws NacosException {
            try {
                Class<?> driverImplClass = Class.forName("com.alibaba.nacos.client.config.NacosConfigService");
                Constructor constructor = driverImplClass.getConstructor(Properties.class);
                ConfigService vendorImpl = (ConfigService)constructor.newInstance(properties);
                return vendorImpl;
            } catch (Throwable var4) {
                throw new NacosException(-400, var4.getMessage());
            }
        }
    NacosConfigService.java中的构造函数进行初始化,同时也初始化了我们的clientWorker;
    public NacosConfigService(Properties properties) throws NacosException {
            String encodeTmp = properties.getProperty("encode");
            if (StringUtils.isBlank(encodeTmp)) {
                this.encode = "UTF-8";
            } else {
                this.encode = encodeTmp.trim();
            }
    
            String namespaceTmp = properties.getProperty("namespace");
            if (StringUtils.isBlank(namespaceTmp)) {
                this.namespace = TenantUtil.getUserTenant();
                properties.put("namespace", this.namespace);
            } else {
                this.namespace = namespaceTmp;
                properties.put("namespace", this.namespace);
            }
    
            this.agent = new ServerHttpAgent(properties);
            this.agent.start();
            this.worker = new ClientWorker(this.agent, this.configFilterChainManager);
        }

    AnnotationNacosPropertySourceBuilder.java

    protected Map<String, Object>[] resolveRuntimeAttributesArray(AnnotatedBeanDefinition beanDefinition, Properties globalNacosProperties) {
            AnnotationMetadata metadata = beanDefinition.getMetadata();
            Set<String> annotationTypes = metadata.getAnnotationTypes();
            List<Map<String, Object>> annotationAttributesList = new LinkedList();
            Iterator var6 = annotationTypes.iterator();
    
            while(var6.hasNext()) {
                String annotationType = (String)var6.next();
                annotationAttributesList.addAll(this.getAnnotationAttributesList(metadata, annotationType));
            }
    
            return (Map[])annotationAttributesList.toArray(new Map[0]);
        }

     以上就是一个过程,后面我们在专题分享他这么多的意义,或者说目的;

    这样子一套跳转下来,一个注解类的解析就结束了,下面我们就获得了这个类的相关东东,那些value,以及property,后面我们就看下他如何取值,以及后续相关操作! 

    NacosUtils.java
    /**
         * Get content from {@link ConfigService} via dataId and groupId
         *
         * @param configService {@link ConfigService}
         * @param dataId        dataId
         * @param groupId       groupId
         * @return If available , return content , or <code>null</code>
         */
        public static String getContent(ConfigService configService, String dataId, String groupId) {
            String content = null;
            try {
                content = configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT);
            } catch (NacosException e) {
                if (logger.isErrorEnabled()) {
                    logger.error("Can't get content from dataId : " + dataId + " , groupId : " + groupId, e);
                }
            }
            return content;
        }
    NacosConfigService.java
     @Override
        public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {
            return getConfigInner(namespace, dataId, group, timeoutMs);
        }

    客户端的代码就是通过这个方式去获取的属性值,只要你坚持没有什么是不可能的,加油!

     private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {
            group = this.null2defaultGroup(group);
            ParamUtils.checkKeyParam(dataId, group);
            ConfigResponse cr = new ConfigResponse();
            cr.setDataId(dataId);
            cr.setTenant(tenant);
            cr.setGroup(group);
    // 优先使用本地配置 String content
    = LocalConfigInfoProcessor.getFailover(this.agent.getName(), dataId, group, tenant); if (content != null) { log.warn(this.agent.getName(), "[get-config] get failover ok, dataId={}, group={}, tenant={}, config={}", new Object[]{dataId, group, tenant, ContentUtils.truncateContent(content)}); cr.setContent(content); this.configFilterChainManager.doFilter((IConfigRequest)null, cr); content = cr.getContent(); return content; } else { try { content = this.worker.getServerConfig(dataId, group, tenant, timeoutMs); cr.setContent(content); this.configFilterChainManager.doFilter((IConfigRequest)null, cr); content = cr.getContent(); return content; } catch (NacosException var9) { if (403 == var9.getErrCode()) { throw var9; } else { log.warn("NACOS-0003", LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0003", "环境问题", "get from server error")); log.warn(this.agent.getName(), "[get-config] get from server error, dataId={}, group={}, tenant={}, msg={}", new Object[]{dataId, group, tenant, var9.toString()}); log.warn(this.agent.getName(), "[get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}", new Object[]{dataId, group, tenant, ContentUtils.truncateContent(content)}); content = LocalConfigInfoProcessor.getSnapshot(this.agent.getName(), dataId, group, tenant); cr.setContent(content); this.configFilterChainManager.doFilter((IConfigRequest)null, cr); content = cr.getContent(); return content; } } } }
    public class LocalConfigInfoProcessor {
    
        private static final Logger LOGGER = LogUtils.logger(LocalConfigInfoProcessor.class);
    
        static public String getFailover(String serverName, String dataId, String group, String tenant) {
            File localPath = getFailoverFile(serverName, dataId, group, tenant);
            if (!localPath.exists() || !localPath.isFile()) {
                return null;
            }
    
            try {
                return readFile(localPath);
            } catch (IOException ioe) {
                LOGGER.error("[" + serverName + "] get failover error, " + localPath, ioe);
                return null;
            }
        }
    }

    还是这个类中的方法

     static File getFailoverFile(String serverName, String dataId, String group, String tenant) {
            File tmp = new File(LOCAL_SNAPSHOT_PATH, serverName + "_nacos");
            tmp = new File(tmp, "data");
            if (StringUtils.isBlank(tenant)) {
                tmp = new File(tmp, "config-data");
            } else {
                tmp = new File(tmp, "config-data-tenant");
                tmp = new File(tmp, tenant);
            }
            return new File(new File(tmp, group), dataId);
        }
     public String getServerConfig(String dataId, String group, String tenant, long readTimeout)
            throws NacosException {
            if (StringUtils.isBlank(group)) {
                group = Constants.DEFAULT_GROUP;
            }
    
            HttpResult result = null;
            try {
                List<String> params = null;
                if (StringUtils.isBlank(tenant)) {
                    params = Arrays.asList("dataId", dataId, "group", group);
                } else {
                    params = Arrays.asList("dataId", dataId, "group", group, "tenant", tenant);
                }
                result = agent.httpGet(Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode(), readTimeout);
            } catch (IOException e) {
                String message = String.format(
                    "[%s] [sub-server] get server config exception, dataId=%s, group=%s, tenant=%s", agent.getName(),
                    dataId, group, tenant);
                LOGGER.error(message, e);
                throw new NacosException(NacosException.SERVER_ERROR, e.getMessage());
            }
    
            switch (result.code) {
                case HttpURLConnection.HTTP_OK:
                    LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, result.content);
                    return result.content;
                case HttpURLConnection.HTTP_NOT_FOUND:
                    LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, null);
                    return null;
                case HttpURLConnection.HTTP_CONFLICT: {
                    LOGGER.error(
                        "[{}] [sub-server-error] get server config being modified concurrently, dataId={}, group={}, "
                            + "tenant={}", agent.getName(), dataId, group, tenant);
                    throw new NacosException(NacosException.CONFLICT,
                        "data being modified, dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
                }
                case HttpURLConnection.HTTP_FORBIDDEN: {
                    LOGGER.error("[{}] [sub-server-error] no right, dataId={}, group={}, tenant={}", agent.getName(), dataId,
                        group, tenant);
                    throw new NacosException(result.code, result.content);
                }
                default: {
                    LOGGER.error("[{}] [sub-server-error]  dataId={}, group={}, tenant={}, code={}", agent.getName(), dataId,
                        group, tenant, result.code);
                    throw new NacosException(result.code,
                        "http error, code=" + result.code + ",dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
                }
            }
    client在取值的话优先通过本地文件的方式去访问,取不到的话再通过http的方式去nacos中去取;这样就是一个取值的闭环了;

    我感觉这样主要是client和nacos部署到一起的方式去解决了!

    下面我们开始分析Nacos的思想,基本上本篇结束怎个Nacos客户端加载的过程就结束了,启动的时候如何取值,下面我们会分析Nacos发布之后,客户端是如何取值的,
    这里我们不妨猜测下,会不会采用了代理模式,我们每次取值的时候,在我们取值前,封装了一部分取值的操作,取值的操作应该就是前面的那套逻辑^_^
    加油,go!

  • 相关阅读:
    BZOJ 1185 [HNOI2007]最小矩形覆盖 ——计算几何
    BZOJ 1007 [HNOI2008]水平可见直线 ——计算几何
    BZOJ 1069 [SCOI2007]最大土地面积 ——计算几何
    BZOJ 2829 信用卡凸包 ——计算几何
    BZOJ 2300 [HAOI2011]防线修建 ——计算几何
    BZOJ 1027 [JSOI2007]合金 ——计算几何
    BZOJ 1043 [HAOI2008]下落的圆盘 ——计算几何
    BZOJ 1294 [SCOI2009]围豆豆Bean ——计算几何
    BZOJ 1043 [HAOI2008]下落的圆盘 ——计算几何
    radius服务器搭建
  • 原文地址:https://www.cnblogs.com/longxok/p/11023659.html
Copyright © 2011-2022 走看看