PropertySourceLocator(SpringCloud中的配置操作)

又是美好的一天呀~
个人博客地址: huanghong.top

内容简介

SpringCloud服务在主程序启动时,会在刷新上下文之前通过扩展点初始化器ApplicationContextInitializer的initialize方法来进行环境相关内容的准备,PropertySourceBootstrapConfiguration作为ApplicationContextInitializer的实现类,在环境准备期间会通过PropertySourceLocator接口在程序启动前来获取应用属性资源并加载到当前Environment中。

eg. SpringCloud在整合Nacos(Config)配置中心,应用在启动过程中会执行Nacos实现的NacosPropertySourceLocator来获取Nacos服务端配置内容并将配置内容加载进当前Environment中,从而实现配置属性的注入功能。

源码分析

prepareContext

应用主程序启动后,在执行至refreshContext刷新上下文之前,首先会进行上下文内容的准备工作。

//org.springframework.boot.SpringApplication#prepareContext
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
      ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments, Banner printedBanner) {
   //上下文环境设置
   context.setEnvironment(environment);
   //上下文扩展
   //1. 手动注入beanNameGenerator实例
   //2. 设置上下文资源加载器resourceLoader
   //3. 设置转换服务ConversionService
   postProcessApplicationContext(context);
   //执行初始化器初始化内容
   applyInitializers(context);
   ...
}

applyInitializers

//org.springframework.boot.SpringApplication#applyInitializers
protected void applyInitializers(ConfigurableApplicationContext context) {
   //获取所有初始化器
   for (ApplicationContextInitializer initializer : getInitializers()) {
      //检测初始化器类型
      Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
            ApplicationContextInitializer.class);
      Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
      //执行初始化器初始化方法
      initializer.initialize(context);
   }
}

PropertySourceBootstrapConfiguration#initialize

//org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration#initialize
public void initialize(ConfigurableApplicationContext applicationContext) {
   List<PropertySource<?>> composite = new ArrayList<>();
   //propertySourceLocators进行排序
   AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
   boolean empty = true;
   //获取上下文环境对象
   ConfigurableEnvironment environment = applicationContext.getEnvironment();
   //遍历处理
   for (PropertySourceLocator locator : this.propertySourceLocators) {
      //获取PropertySource集合
      Collection<PropertySource<?>> source = locator.locateCollection(environment);
      if (source == null || source.size() == 0) {
         continue;
      }
      List<PropertySource<?>> sourceList = new ArrayList<>();
      //遍历PropertySource集合
      for (PropertySource<?> p : source) {
         //如果为EnumerablePropertySource类型对象, 则构建一个BootstrapPropertySource实例添加进集合中
         if (p instanceof EnumerablePropertySource) {
            EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) p;
            sourceList.add(new BootstrapPropertySource<>(enumerable));
         }
         else {
            //否则构建一个SimpleBootstrapPropertySource实例并添加进集合中
            sourceList.add(new SimpleBootstrapPropertySource(p));
         }
      }
      logger.info("Located property source: " + sourceList);
      composite.addAll(sourceList);
      empty = false;
   }
   //获取属性集合不为空
   if (!empty) {
      //获取当前环境所有属性源
      MutablePropertySources propertySources = environment.getPropertySources();
      String logConfig = environment.resolvePlaceholders("${logging.config:}");
      LogFile logFile = LogFile.get(environment);
      for (PropertySource<?> p : environment.getPropertySources()) {
         //移除bootstrapProperties相关属性源
         if (p.getName().startsWith(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
            propertySources.remove(p.getName());
         }
      }
      //添加上文获取到的属性源集合至当前环境中
      insertPropertySources(propertySources, composite);
      //重新初始化日志系统
      reinitializeLoggingSystem(environment, logConfig, logFile);
      //设置日志等级
      setLogLevels(applicationContext, environment);
      //处理指定环境 TODO
      handleIncludedProfiles(environment);
   }
}

locateCollection

//org.springframework.cloud.bootstrap.config.PropertySourceLocator#locateCollection(org.springframework.cloud.bootstrap.config.PropertySourceLocator, org.springframework.core.env.Environment)
static Collection<PropertySource<?>> locateCollection(PropertySourceLocator locator, Environment environment) {
   //执行具体实现方法返回PropertySource对象
   PropertySource<?> propertySource = locator.locate(environment);
   if (propertySource == null) {
      return Collections.emptyList();
   }
   //如果是复合对象(对象中包含多个PropertySource),过滤空值并逐个添加返回
   if (CompositePropertySource.class.isInstance(propertySource)) {
      Collection<PropertySource<?>> sources = ((CompositePropertySource) propertySource).getPropertySources();
      List<PropertySource<?>> filteredSources = new ArrayList<>();
      for (PropertySource<?> p : sources) {
         if (p != null) {
            filteredSources.add(p);
         }
      }
      return filteredSources;
   }
   else {
      //返回结果集
      return Arrays.asList(propertySource);
   }
}
Nacos示例

image-20230331101219913

当前Environment持有的PropertySource

image-20230331101558591

insertPropertySources

//org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration#insertPropertySources
private void insertPropertySources(MutablePropertySources propertySources, List<PropertySource<?>> composite) {
   MutablePropertySources incoming = new MutablePropertySources();
   List<PropertySource<?>> reversedComposite = new ArrayList<>(composite);
   // Reverse the list so that when we call addFirst below we are maintaining the
   // same order of PropertySources
   // Wherever we call addLast we can use the order in the List since the first item
   // will end up before the rest
   //反转集合,后续可以按照原顺序加入当前环境集合中
   Collections.reverse(reversedComposite);
   for (PropertySource<?> p : reversedComposite) {
      incoming.addFirst(p);
   }
   //overrideSystemProperties: 外部属性可以覆盖系统属性 默认true
   //allowOverride: 允许覆盖 默认true
   //overrideNone: 当allowOverride为true时,外部属性应该具有最低优先级,并且不应该覆盖任何现有的属性源(包括本地配置文件)
   PropertySourceBootstrapProperties remoteProperties = new PropertySourceBootstrapProperties();
   Binder.get(environment(incoming)).bind("spring.cloud.config", Bindable.ofInstance(remoteProperties));
   //默认赋值方式
   if (!remoteProperties.isAllowOverride()
         || (!remoteProperties.isOverrideNone() && remoteProperties.isOverrideSystemProperties())) {
      for (PropertySource<?> p : reversedComposite) {
         //添加进当前环境属性源中
         propertySources.addFirst(p);
      }
      return;
   }
   if (remoteProperties.isOverrideNone()) {
      for (PropertySource<?> p : composite) {
         propertySources.addLast(p);
      }
      return;
   }
   if (propertySources.contains(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) {
      if (!remoteProperties.isOverrideSystemProperties()) {
         for (PropertySource<?> p : reversedComposite) {
            propertySources.addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, p);
         }
      }
      else {
         for (PropertySource<?> p : composite) {
            propertySources.addBefore(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, p);
         }
      }
   }
   else {
      for (PropertySource<?> p : composite) {
         propertySources.addLast(p);
      }
   }
}

ConfigurationProperties

基于ConfigurationProperties的属性填充是发生在Bean初始化的期间,Bean属性的配置填充是通过ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization来完成的。

postProcessBeforeInitialization

//org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
   return bean;
}

bind

//org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#bind
private void bind(ConfigurationPropertiesBean bean) {
   if (bean == null || hasBoundValueObject(bean.getName())) {
      return;
   }
   Assert.state(bean.getBindMethod() == BindMethod.JAVA_BEAN, "Cannot bind @ConfigurationProperties for bean '"
         + bean.getName() + "'. Ensure that @ConstructorBinding has not been applied to regular bean");
   try {
      //通过配置文件中的配置属性重新绑定Bean的属性值
      this.binder.bind(bean);
   }
   catch (Exception ex) {
      throw new ConfigurationPropertiesBindException(bean, ex);
   }
}

感谢阅读完本篇文章!!!
个人博客地址: huanghong.top

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢正常冰的冰美式

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值