美文网首页
spring boot Appollo加载过程

spring boot Appollo加载过程

作者: 草祭木初 | 来源:发表于2021-03-19 09:30 被阅读0次

    学习Appollo是怎么加载配置的

    com.ctrip.framework.apollo:apollo-client:1.0.0

    Appollo 文档

    先看一下spring.fatories

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.ctrip.framework.apollo.spring.boot.ApolloAutoConfiguration
    org.springframework.context.ApplicationContextInitializer=\
    com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer
    

    org.springframework.context.ApplicationContextInitializer=
    com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer
    这句是在项目已启动,配置信息加载完就执行ApolloApplicationContextInitializer类的initialize方法

    ApolloApplicationContextInitializer

    public class ApolloApplicationContextInitializer implements
        ApplicationContextInitializer<ConfigurableApplicationContext> {
      private static final Logger logger = LoggerFactory.getLogger(ApolloApplicationContextInitializer.class);
      private static final Splitter NAMESPACE_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();
      private static final String[] APOLLO_SYSTEM_PROPERTIES = {"app.id", ConfigConsts.APOLLO_CLUSTER_KEY,
          "apollo.cacheDir", ConfigConsts.APOLLO_META_KEY};
    
      private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector
          .getInstance(ConfigPropertySourceFactory.class);
    
      @Override
      public void initialize(ConfigurableApplicationContext context) {
        ConfigurableEnvironment environment = context.getEnvironment();
    
        initializeSystemProperty(environment);
    
        String enabled = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, "false");
        if (!Boolean.valueOf(enabled)) {
          logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED);
          return;
        }
        logger.debug("Apollo bootstrap config is enabled for context {}", context);
    
        if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
          //already initialized
          return;
        }
    
        String namespaces = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, ConfigConsts.NAMESPACE_APPLICATION);
        logger.debug("Apollo bootstrap namespaces: {}", namespaces);
        List<String> namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);
    
        CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
        for (String namespace : namespaceList) {
          Config config = ConfigService.getConfig(namespace);
    
          composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
        }
    
        environment.getPropertySources().addFirst(composite);
      }
    
      /**
       * To fill system properties from environment config
       */
      void initializeSystemProperty(ConfigurableEnvironment environment) {
        for (String propertyName : APOLLO_SYSTEM_PROPERTIES) {
          fillSystemPropertyFromEnvironment(environment, propertyName);
        }
      }
    
      private void fillSystemPropertyFromEnvironment(ConfigurableEnvironment environment, String propertyName) {
        if (System.getProperty(propertyName) != null) {
          return;
        }
    
        String propertyValue = environment.getProperty(propertyName);
    
        if (Strings.isNullOrEmpty(propertyValue)) {
          return;
        }
    
        System.setProperty(propertyName, propertyValue);
      }
    }
    

    首先看这块

    String enabled = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, "false");
        if (!Boolean.valueOf(enabled)) {
          logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED);
          return;
        }
    

    apollo.bootstrap.enabled = true

    如果enabled 没有配置的话,直接返回。
    看起来是不启动Appollo了,但是并不是。后面会讲。

    然后就是这句
    真正发起请求,到Appollo中心取配置信息

     Config config = ConfigService.getConfig(namespace);
    

    接下来看
    apollo.bootstrap.enabled = false 时,客户端是怎么样拉取配置的

    @SpringBootApplication
    @EnableApolloConfig
    public class MainApplication {
        public static void main(String[] args) {
            SpringApplication sa = new SpringApplication(MainApplication.class);
            sa.addInitializers(new TestApplicationContextInitializer());
            sa.run(args);
    
        }
    }
    

    秘密就在 @EnableApolloConfig

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Import(ApolloConfigRegistrar.class)
    public @interface EnableApolloConfig {
      /**
       * Apollo namespaces to inject configuration into Spring Property Sources.
       */
      String[] value() default {ConfigConsts.NAMESPACE_APPLICATION};
    
      /**
       * The order of the apollo config, default is {@link Ordered#LOWEST_PRECEDENCE}, which is Integer.MAX_VALUE.
       * If there are properties with the same name in different apollo configs, the apollo config with smaller order wins.
       * @return
       */
      int order() default Ordered.LOWEST_PRECEDENCE;
    }
    

    @Import:执行的时间点是在 ApolloApplicationContextInitializer 之后,其他Bean加载之前
    再看下
    ApolloConfigRegistrar
    它实现了ImportBeanDefinitionRegistrar接口
    可以通过BeanDefinitionRegistry 提前注册一些Bean定义到Spring容器里

    public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar {
      @Override
      public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata
            .getAnnotationAttributes(EnableApolloConfig.class.getName()));
        String[] namespaces = attributes.getStringArray("value");
        int order = attributes.getNumber("order");
        PropertySourcesProcessor.addNamespaces(Lists.newArrayList(namespaces), order);
    
        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
            PropertySourcesPlaceholderConfigurer.class);
    
        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(),
            PropertySourcesProcessor.class);
    
        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(),
            ApolloAnnotationProcessor.class);
    
        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(), SpringValueProcessor.class);
        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class.getName(), SpringValueDefinitionProcessor.class);
    
        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(),
                ApolloJsonValueProcessor.class);
      }
    }
    

    先加载命名空间
    再加载配置项
    然后

    BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(),
            PropertySourcesProcessor.class);
    

    注册了,PropertySourcesProcessor会被提前加载

    PropertySourcesProcessor
    

    看下它
    它实现了 BeanFactoryPostProcessor,EnvironmentAware, PriorityOrdered

    • PriorityOrdered:定义加载顺序,也就是 有多个类实现了BeanFactoryPostProcessor接口的话,这个接口 会尽可能的先执行
    • EnvironmentAware:注入Environment对象
    • BeanFactoryPostProcessor:实现了postProcessBeanFactory方法。会在ApplicationContextInitializer 与 @Import加载的类之后执行

    下面是PropertySourcesProcessor的代码

    public class PropertySourcesProcessor implements BeanFactoryPostProcessor, EnvironmentAware, PriorityOrdered {
      private static final Multimap<Integer, String> NAMESPACE_NAMES = LinkedHashMultimap.create();
      private static final AtomicBoolean INITIALIZED = new AtomicBoolean(false);
    
      private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector
          .getInstance(ConfigPropertySourceFactory.class);
      private final ConfigUtil configUtil = ApolloInjector.getInstance(ConfigUtil.class);
      private ConfigurableEnvironment environment;
    
      public static boolean addNamespaces(Collection<String> namespaces, int order) {
        return NAMESPACE_NAMES.putAll(order, namespaces);
      }
    
      @Override
      public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        if (INITIALIZED.compareAndSet(false, true)) {
          initializePropertySources();
    
          initializeAutoUpdatePropertiesFeature(beanFactory);
        }
      }
    
      private void initializePropertySources() {
        if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME)) {
          //already initialized
          return;
        }
        CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME);
    
        //sort by order asc
        ImmutableSortedSet<Integer> orders = ImmutableSortedSet.copyOf(NAMESPACE_NAMES.keySet());
        Iterator<Integer> iterator = orders.iterator();
    
        while (iterator.hasNext()) {
          int order = iterator.next();
          for (String namespace : NAMESPACE_NAMES.get(order)) {
            Config config = ConfigService.getConfig(namespace);
    
            composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
          }
        }
    
        // add after the bootstrap property source or to the first
        if (environment.getPropertySources()
            .contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
          environment.getPropertySources()
              .addAfter(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME, composite);
        } else {
          environment.getPropertySources().addFirst(composite);
        }
      }
    
      private void initializeAutoUpdatePropertiesFeature(ConfigurableListableBeanFactory beanFactory) {
        if (!configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
          return;
        }
    
        AutoUpdateConfigChangeListener autoUpdateConfigChangeListener = new AutoUpdateConfigChangeListener(
            environment, beanFactory);
    
        List<ConfigPropertySource> configPropertySources = configPropertySourceFactory.getAllConfigPropertySources();
        for (ConfigPropertySource configPropertySource : configPropertySources) {
          configPropertySource.addChangeListener(autoUpdateConfigChangeListener);
        }
      }
    
      @Override
      public void setEnvironment(Environment environment) {
        //it is safe enough to cast as all known environment is derived from ConfigurableEnvironment
        this.environment = (ConfigurableEnvironment) environment;
      }
    
      //only for test
      private static void reset() {
        NAMESPACE_NAMES.clear();
        INITIALIZED.set(false);
      }
    
      @Override
      public int getOrder() {
        //make it as early as possible
        return Ordered.HIGHEST_PRECEDENCE;
      }
    }
    

    可以看到这里也有这段, 拉取配置的代码

    Config config = ConfigService.getConfig(namespace);
    

    相关文章

      网友评论

          本文标题:spring boot Appollo加载过程

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