zoukankan      html  css  js  c++  java
  • nacosconfig 配置数据加载

    我们从SpringBoot的run方法入手,主体逻辑步骤为:

    1.prepareEnvironment

    2.createApplicationContext

    3.prepareContext

    4.refreshContext

    5.afterRefresh

    prepareEnvironment

    org.springframework.boot.SpringApplication#run(java.lang.String...) =》org.springframework.boot.SpringApplication#prepareEnvironment =》org.springframework.boot.SpringApplicationRunListeners#environmentPrepared =》org.springframework.boot.context.event.EventPublishingRunListener#environmentPrepared

    在这里通过org.springframework.context.event.SimpleApplicationEventMulticaster广播ApplicationEnvironmentPreparedEvent事件。

    那么,事件的监听者有哪些?通过代码走读发现,事件的监听者在EventPublishingRunListener构造方法中通过SpringApplication.getListeners()获取。那么,SpringApplication的监听者又是哪来的?

    同样,走读代码如下,通过springfactories机制加载org.springframework.context.ApplicationListener实现:

     这其中就有一个Spring Cloud扩展的实现:

     这个listener监听的正是上文提到的环境准备事件ApplicationEnvironmentPreparedEvent:

     org.springframework.cloud.bootstrap.BootstrapApplicationListener#onApplicationEvent主要通过构建临时ApplicationContext,利用Spring自带的IOC能力,查找以SpringFactories方式扩展org.springframework.cloud.bootstrap.BootstrapConfiguration注解的class,BootstrapApplicationListener主要目的是查找ApplicationContextInitializer并加入到SpringApplication的initializers列表中,用于监听后续正式Context事件

    代码调用路径:org.springframework.cloud.bootstrap.BootstrapApplicationListener#onApplicationEvent =》 org.springframework.cloud.bootstrap.BootstrapApplicationListener#bootstrapServiceContext

    这里通过SpringApplicationBuilder构建临时Context,build的source为org.springframework.cloud.bootstrap.BootstrapImportSelectorConfiguration

     

     这里通过org.springframework.cloud.bootstrap.BootstrapImportSelector加载返回字符串对应的class实例到IOC容器。至于@Import注解的分析见另外一篇博文。

    @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            // Use names and ensure unique to protect against duplicates
    // 获取通过SpringFactories方式以org.springframework.cloud.bootstrap.BootstrapConfiguration为key扩展的所有class类名
    List<String> names = new ArrayList<>(SpringFactoriesLoader .loadFactoryNames(BootstrapConfiguration.class, classLoader));
    // 这里有个扩展点,可以通过spring.cloud.bootstrap.sources加载Bootstrap相关bean names.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(
    this.environment.getProperty("spring.cloud.bootstrap.sources", "")))); List<OrderedAnnotatedElement> elements = new ArrayList<>(); for (String name : names) { try { elements.add( new OrderedAnnotatedElement(this.metadataReaderFactory, name)); } catch (IOException e) { continue; } } AnnotationAwareOrderComparator.sort(elements); String[] classNames = elements.stream().map(e -> e.name).toArray(String[]::new); return classNames; }

    这里有个跟本篇主题相关的Spring Cloud扩展BootstrapConfiguration的两个实现:

     构建完context后回到onApplicationEvent方法,调用org.springframework.cloud.bootstrap.BootstrapApplicationListener#apply。

    回到org.springframework.boot.SpringApplication#run(java.lang.String...)方法,

     prepareContext

    了解spring源码的人应该知道,bean的创建等都是在Context的refresh中。这里再refresh之前做些环境数据的准备工作。

     org.springframework.boot.SpringApplication#prepareContext =》org.springframework.boot.SpringApplication#applyInitializers

    循环调用所有initializer的initialize方法:

     看下上文提到的Spring Cloud扩展org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration#initialize,重点代码片段如下,通过propertySourceLocators获取PropertySource:

     问题来了,propertySourceLocators是哪里来的?还记得PropertySourceBootstrapConfiguration是怎么构建的吗?没错,就是以org.springframework.cloud.bootstrap.BootstrapImportSelectorConfiguration为source,创建临时Context加载生成的bean,这里会加载所有以org.springframework.cloud.bootstrap.BootstrapConfiguration为key的bean,我们的主角登场了,Spring Cloud Alibaba Nacos Config扩展了Spring Cloud的这个点:

     com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration自动创建了NacosPropertySourceLocator:

     最终会调用com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#locate:

    @Override
        public PropertySource<?> locate(Environment env) {
            nacosConfigProperties.setEnvironment(env);
            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();
            // 优先使用配置的spring.cloud.nacos.config.prefix
            String dataIdPrefix = nacosConfigProperties.getPrefix();
    // 如果没有配置prefix,尝试使用spring.cloud.nacos.config.name
    if (StringUtils.isEmpty(dataIdPrefix)) { dataIdPrefix = name; } // 还是没有的话,使用spring.application.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; }

    com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadApplicationConfiguration =》 com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosDataIfPresent =》com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosPropertySource =》com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#build =》com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#loadNacosData =》com.alibaba.nacos.client.config.NacosConfigService#getConfig

    最终通过nacos client的configService从服务端获取数据并封装成PropertySource返回。

  • 相关阅读:
    Python error: Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall.bat)解决方案
    3-Longest Substring Without Repeating Characters @LeetCode
    2-Add Two Numbers @LeetCode
    1-Two Sum @LeetCode
    DES原理及代码实现
    Linux网络篇,ssh原理及应用
    虚拟机如何通过“仅主机”模式上网
    MySQL入门,第八部分,多表查询(二)
    MySQL入门,第八部分,多表查询(一)
    MySQL入门,第七部分,单表查询
  • 原文地址:https://www.cnblogs.com/reboot30/p/15133680.html
Copyright © 2011-2022 走看看