application.properties和bootstrap.properties的加载时机

目录

父容器加载BootstrapApplicationListener

配置文件加载ConfigFileApplicationListener

配置类加载BootstrapImportSelectorConfiguration


看默认情况,不论使用参数更改的情况(spring.config.name)

纯粹的SpringBoot主要就是自动配置,加载application.propertiesspring.factories中key为EnableAutoConfiguration的配置类进行bean的自动装配,并不涉及bootstrapbootstrap配置文件是SpringCloud扩展的配置文件,优先于application.properties加载,应用场景例如nacos配置中心的配置属性须在bootstrap.properties中配置

下边来看源码是怎么优先加载的

跟随启动类到run方法org.springframework.boot.SpringApplication#run,在prepareEnvironment方法中构建环境变量对象和加载配置文件

 org.springframework.boot.SpringApplication#prepareEnvironment

创建Environment对象,通过各种监听器来加载不同的配置变量

监听器列表debug如下,第四位ConfigFile监听器即就是加载配置文件(不论是bootstrap还是application都是由它加载)的监听器,优先级最高的Bootstrap监听器才是本次的重点

父容器加载BootstrapApplicationListener

org.springframework.cloud.bootstrap.BootstrapApplicationListener

只处理EnvironmentPrepare事件 

创建了一个属于bootstrap的新容器

	public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
		ConfigurableEnvironment environment = event.getEnvironment();
        // 是否开启bootstrap配置,默认开启
		if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,
				true)) {
			return;
		}

        // 标志位,如果当前环境变量有bootstrap标识,则跳过本类处理,这个标志位往下看就行
		// BOOTSTRAP_PROPERTY_SOURCE_NAME = bootstrap
		if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
			return;
		}
		ConfigurableApplicationContext context = null;
		String configName = environment
				.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
        
        // 省略我不懂的代码
		// 。。。。

		if (context == null) {
            // 新创建一个bootstrap的容器
			context = bootstrapServiceContext(environment, event.getSpringApplication(),
					configName);
			event.getSpringApplication()
					.addListeners(new CloseContextOnFailureApplicationListener(context));
		}

		apply(context, event.getSpringApplication(), environment);
	}

org.springframework.cloud.bootstrap.BootstrapApplicationListener#bootstrapServiceContext

其中新创建了一个SpringApplication,设置配置文件名为bootstrap,又引入了BootstrapImportSelectorConfiguration配置类,最后执行run方法

	private ConfigurableApplicationContext bootstrapServiceContext(
			ConfigurableEnvironment environment, final SpringApplication application,
			String configName) {
		StandardEnvironment bootstrapEnvironment = new StandardEnvironment();
		MutablePropertySources bootstrapProperties = bootstrapEnvironment
				.getPropertySources();
		for (PropertySource<?> source : bootstrapProperties) {
			bootstrapProperties.remove(source.getName());
		}

        // 设置容器的环境
        // 配置文件名为bootstrap\配置文件地址        
		String configLocation = environment
				.resolvePlaceholders("${spring.cloud.bootstrap.location:}");
		String configAdditionalLocation = environment
				.resolvePlaceholders("${spring.cloud.bootstrap.additional-location:}");

		Map<String, Object> bootstrapMap = new HashMap<>();
		bootstrapMap.put("spring.config.name", configName);//配置文件名,默认bootstrap
		bootstrapMap.put("spring.main.web-application-type", "none");
		if (StringUtils.hasText(configLocation)) {
			bootstrapMap.put("spring.config.location", configLocation);
		}
		if (StringUtils.hasText(configAdditionalLocation)) {
			bootstrapMap.put("spring.config.additional-location",
					configAdditionalLocation);
		}

        // BOOTSTRAP_PROPERTY_SOURCE_NAME = bootstrap
        // 也是上个方法的标志位 
		bootstrapProperties.addFirst(
				new MapPropertySource(BOOTSTRAP_PROPERTY_SOURCE_NAME, bootstrapMap));
		for (PropertySource<?> source : environment.getPropertySources()) {
			if (source instanceof StubPropertySource) {
				continue;
			}
			bootstrapProperties.addLast(source);
		}

        // 这里重新使用SpringAoolication的建造器重新构建了一个boot容器
		// TODO: is it possible or sensible to share a ResourceLoader?
		SpringApplicationBuilder builder = new SpringApplicationBuilder()
				.profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
				.environment(bootstrapEnvironment)
				// Don't use the default properties in this builder
				.registerShutdownHook(false).logStartupInfo(false)
				.web(WebApplicationType.NONE);
		final SpringApplication builderApplication = builder.application();
		if (builderApplication.getMainApplicationClass() == null) {
			builder.main(application.getMainApplicationClass());
		}
		if (environment.getPropertySources().contains("refreshArgs")) {
			builderApplication
					.setListeners(filterListeners(builderApplication.getListeners()));
		}

        // 为新容器引入BootstrapImportSelectorConfiguration配置类,执行run方法
		builder.sources(BootstrapImportSelectorConfiguration.class);
		final ConfigurableApplicationContext context = builder.run();

        // 设置容器id,父子关系,移除标志位
		context.setId("bootstrap");
		addAncestorInitializer(application, context);
		bootstrapProperties.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
		mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties);
		return context;
	}

以上代码,知道了SpringCloud在启动时会新创建一个父容器来加一些Cloud需要的配置,接下来从配置文件加载和配置类加载来看父子容器的区别

配置文件加载ConfigFileApplicationListener

首先它处理两个事件,我们只关注环境加载事件

跟代码

 

这里在路径下,根据getSearchName返回的文件名进行加载文件 

 下边逻辑如果当前环境存在参数spring.config.name则使用参数的文件名进行加载,那刚才SpringCloud的新容器设置了参数=boostrap,所以在父容器中会加载bootstrap.properties文件,而在子容器中会使用默认的application.properties进行加载

	public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
    private static final String DEFAULT_NAMES = "application";    
    private Set<String> getSearchNames() {
			if (this.environment.containsProperty(CONFIG_NAME_PROPERTY)) {
				String property = this.environment.getProperty(CONFIG_NAME_PROPERTY);
				Set<String> names = asResolvedSet(property, null);
				names.forEach(this::assertValidConfigName);
				return names;
			}
			return asResolvedSet(ConfigFileApplicationListener.this.names, DEFAULT_NAMES);
		}

配置类加载BootstrapImportSelectorConfiguration

在启动类中会设置@EnableAutoConfiguration@ComponentScan来自动配置和扫描各种bean,而在父容器创建的时候只引入了BootstrapImportSelectorConfiguration

EnableAutoConfiguration类似,引入了Selector来进行spring.factories文件配置类的加载

但是与EnableAutoConfiguration不同的是Bootstrap的代码如下,查询的是spring.factories中key为BootstrapConfiguration的配置类

 这也是nacos配置中心得在bootstrap.properties中配置的原因,看代码如下

 nacos的配置属性类NacosConfigProperties

 自动加载前缀为spring.cloud.nacos.config的属性

 但是这个NacosConfigProperties类在初始化后会执行@PostConstruct方法

 如果bootstrap.properties环境变量未配置nacos配置中心地址,则会默认设置为localhost:8848

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值