disconf启动流程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/peerless_hero/article/details/78481873

如图所示,applicationContext.xml文件中注入了3个和disconf相关的bean。在容器启动的时候,这3个bean将被实例化。
配置

启动流程如下:
流程

loadConfig

该阶段导入配置,包括:

(1)导入系统配置disconf_sys.properties的数据,如果存在系统参数或命令行导入,则覆盖properties文件导入的数据。

(2)校验系统配置

(3)导入用户配置disconf.properties的数据,如果存在系统参数或命令行导入,则覆盖properties文件导入的数据。

(4)校验用户配置

这样,DisClientConfig对象实例就有了disconf_sys.properties和disconf.properties的参数值。

firstScan

该阶段主要下载配置文件并将参数注入到仓库中。

    /**
     * 第一次扫描,静态扫描 for annotation config
     */
    protected synchronized void firstScan(List<String> scanPackageList) {

        // 该函数不能调用两次
        if (isFirstInit) {
            LOGGER.info("DisConfMgr has been init, ignore........");
            return;
        }

        try {

            // 导入配置
            ConfigMgr.init();

            LOGGER.info("******************************* DISCONF START FIRST SCAN *******************************");

            // registry
            Registry registry = RegistryFactory.getSpringRegistry(applicationContext);

            // 扫描器
            scanMgr = ScanFactory.getScanMgr(registry);

            // 第一次扫描并入库
            scanMgr.firstScan(scanPackageList);

            // 获取数据/注入/Watch
            disconfCoreMgr = DisconfCoreFactory.getDisconfCoreMgr(registry);
            disconfCoreMgr.process(true);

            //
            isFirstInit = true;

            LOGGER.info("******************************* DISCONF END FIRST SCAN *******************************");

        } catch (Exception e) {

            LOGGER.error(e.toString(), e);
            throw new RuntimeException(e);
        }
    }

(1)构造一个扫描器scanMgr,staticScannerMgrList维护了配置文件扫描器、配置项扫描器、非注解托管的配置文件扫描器。

(2)进行第一次扫描,扫描scanPackage路径下的加了注解的DisconfFile class,DisconfFileItem method,DisconfItem method等信息。ScanStaticModel分组存储这些扫描信息,再分析出配置文件与配置文件中的Field的Method的MAP–disconfFileItemMap。

(3)通过静态方法StaticScannerFileMgrImpl.transformScanFile转换配置文件,返回对象disconfCenterFile,内容包括disConfCommonModel(app,env,version),url,fields和keyMaps等。

(4)获取配置文件仓库算子,transformScanData方法调用storeOneFile方法存储一个配置文件。

    /**
     * 存储 一个配置文件
     */
    public void storeOneFile(DisconfCenterBaseModel disconfCenterBaseModel) {

        DisconfCenterFile disconfCenterFile = (DisconfCenterFile) disconfCenterBaseModel;

        String fileName = disconfCenterFile.getFileName();

        if (confFileMap.containsKey(fileName)) {

            String errorMessage = "There are two same fileName key!!!! " + "first: " + confFileMap.get(fileName).toString() +
                    "\n, Second: " + disconfCenterFile.toString();
            LOGGER.error(errorMessage);

            // 不允许出现两个同名的文件
            throw new IllegalStateException(errorMessage);
        } else {
            confFileMap.put(fileName, disconfCenterFile);
        }
    }

(5)遍历执行processOneItem方法更新一个配置文件,三步骤:获取远程的所有配置数据、注入到仓库中、进行Watch 配置。

注:
1.开启disconf才需要远程下载, 否则就本地就好。注入到仓库操作从设定目录下读取文件异常后, 会尝试从download目录下读取。

2.开启disconf才需要进行watch。

register java bean

    /**
     * 第一次扫描<br/>
     * 在Spring内部的Bean定义初始化后执行,这样是最高优先级的
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        // 为了做兼容
        DisconfCenterHostFilesStore.getInstance().addJustHostFileSet(fileList);

        List<String> scanPackList = StringUtil.parseStringToStringList(scanPackage, SCAN_SPLIT_TOKEN);
        // unique
        Set<String> hs = new HashSet<String>();
        hs.addAll(scanPackList);
        scanPackList.clear();
        scanPackList.addAll(hs);

        // 进行扫描
        DisconfMgr.getInstance().setApplicationContext(applicationContext);
        DisconfMgr.getInstance().firstScan(scanPackList);

        // register java bean
        registerAspect(registry);
    }

reloadableScan

该阶段处理非注解托管的配置文件。

   /**
     * reloadable config file scan, for xml config
     */
    public synchronized void reloadableScan(String fileName, String appName, String version) {

        if (!isFirstInit) {
            return;
        }

        // 不开启disconf也可以使用本地配置进行注册中中央仓库
        // if (DisClientConfig.getInstance().ENABLE_DISCONF) {
            try {

                if (!DisClientConfig.getInstance().getIgnoreDisconfKeySet().contains(fileName)) {

                    if (scanMgr != null) {
                        scanMgr.reloadableScan(fileName, appName, version);
                    }

                    if (disconfCoreMgr != null) {
                        disconfCoreMgr.processFile(fileName);
                    }
                    LOGGER.debug("disconf reloadable file: {}", fileName);
                }

            } catch (Exception e) {

                LOGGER.error(e.toString(), e);
                throw new RuntimeException(e);
            }
        // }
    }

(1)通过静态方法StaticScannerNonAnnotationFileMgrImpl.getDisconfCenterFile返回配置文件disconfCenterFile,内容包括disConfCommonModel(app,env,version),url等。

(2)获取配置文件仓库算子,transformScanData方法调用storeOneFile方法存储一个配置文件。

(3)执行processOneItem方法更新一个配置文件,三步骤:获取远程的所有配置数据、注入到仓库中、进行Watch 配置。

注:
1.开启disconf才需要远程下载, 否则就本地就好。注入到仓库操作从设定目录下读取文件异常后, 会尝试从download目录下读取。

2.开启disconf才需要进行watch。

3.流程基本和firstScan相似,部分源码参照上面,不再赘述。

4.非注解托管的配置文件依然需要org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer去替换xml文件中的占位符。
这里写图片描述

secondScan

该阶段主要做了两件事情:
(1)将回调函数实例化并写入仓库。关于disconf回调

    /**
     * 扫描更新回调函数
     */
    public static void scanUpdateCallbacks(ScanStaticModel scanModel, Registry registry) {

        // 扫描出来
        ScanDynamicModel scanDynamicModel = analysis4DisconfUpdate(scanModel, registry);

        // 写到仓库中
        transformUpdateService(scanDynamicModel.getDisconfUpdateServiceInverseIndexMap());
        transformPipelineService(scanDynamicModel.getDisconfUpdatePipeline());
    }

(2)将仓库confFileMap里的数据注入到配置项、配置文件的实体中。

    /**
     * 为某个配置文件进行注入实例中
     */
    private void inject2OneConf(String fileName, DisconfCenterFile disconfCenterFile) {

        if (disconfCenterFile == null) {
            return;
        }

        try {

            //
            // 获取实例
            //

            if (!disconfCenterFile.isTaggedWithNonAnnotationFile()) { 
                Object object;
                try {

                    object = disconfCenterFile.getObject();
                    if (object == null) {
                        object = registry.getFirstByType(disconfCenterFile.getCls(), false, true);
                    }

                } catch (Exception e) {

                    LOGGER.error(e.toString());
                    object = null;
                }

                // 注入实体中
                disconfStoreProcessor.inject2Instance(object, fileName);
            }

        } catch (Exception e) {
            LOGGER.warn(e.toString(), e);
        }
    }
展开阅读全文

没有更多推荐了,返回首页