2023-09-15
原文作者:王伟王胖胖 原文地址:https://blog.csdn.net/wangwei19871103/article/details/105727617

基本处理流程

202309152315034411.png

BootstrapApplicationListener

这个是springcloud中的自动配置监听器之一,这个就是可以做远程配置的。

202309152315052342.png
而且他排序在ConfigFileApplicationListener前面的,这个是要点,因为ConfigFileApplicationListener会进行文件的加载,如果我想添加一些新的配置文件,就可以在BootstrapApplicationListener中添加,比如bootstrap配置文件就是这么做的。

202309152315058483.png

onApplicationEvent

看起来好像没做多少东西,其实里面重新创建了一个SpringApplication上下文呢,为了添加BootstrapImportSelectorConfiguration配置类,里面会注册所有BootstrapConfiguration类型的配置类。然后进行上下文的runConfigFileApplicationListener会去加载bootstrap的配置文件,整合初始化器到新上下文,具体慢慢分析。

    public static final String BOOTSTRAP_PROPERTY_SOURCE_NAME = "bootstrap";
    
    
    	@Override
    	public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
    		ConfigurableEnvironment environment = event.getEnvironment();
    		if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,
    				true)) {//默认是true
    			return;
    		}
    		// 不会重复执行,如果有bootstrap属性名了就返回
    		if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
    			return;
    		}
    		ConfigurableApplicationContext context = null;
    		String configName = environment
    				.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
    		for (ApplicationContextInitializer<?> initializer : event.getSpringApplication()
    				.getInitializers()) {//从父上下文初始化器里获取
    			if (initializer instanceof ParentContextApplicationContextInitializer) {
    				context = findBootstrapContext(
    						(ParentContextApplicationContextInitializer) initializer,
    						configName);
    			}
    		}
    		if (context == null) {
    			context = bootstrapServiceContext(environment, event.getSpringApplication(),
    					configName);
    			event.getSpringApplication()
    					.addListeners(new CloseContextOnFailureApplicationListener(context));
    		}
    
    		apply(context, event.getSpringApplication(), environment);
    	}

bootstrapServiceContext创建新上下文一

一般没有父上下文初始化,所以要重新创建一个上下文,为的就是来加载一些配置文件。
首先是创建一个新的环境,将里面的属性源删除干净,然后放入spring.config.name=bootstrap的属性源,如果有spring.config.locationspring.config.additional-location也一起放入,封装成一个MapPropertySource属性源namebootstrap,放进新环境属性源里,然后把老的环境属性源放入到新的里。

    //初始化一个上下文
    	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());
    		}
    		String configLocation = environment
    				.resolvePlaceholders("${spring.cloud.bootstrap.location:}");
    		String configAdditionalLocation = environment
    				.resolvePlaceholders("${spring.cloud.bootstrap.additional-location:}");
    		Map<String, Object> bootstrapMap = new HashMap<>();
    		//添加配置名bootstrap
    		bootstrapMap.put("spring.config.name", configName);
    		
    		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);
    		}
    		bootstrapProperties.addFirst(
    				new MapPropertySource(BOOTSTRAP_PROPERTY_SOURCE_NAME, bootstrapMap));
    		for (PropertySource<?> source : environment.getPropertySources()) {
    			if (source instanceof StubPropertySource) {
    				continue;
    			}
    			bootstrapProperties.addLast(source);//老的放进新的里
    		}

202309152315068334.png

bootstrapServiceContext创建新上下文二

创建一个SpringApplicationBuilder,就是建造者模式,里面就是创建SpringApplication的,然后设置一些属性,是一个最简单的一半上下文设置,然后设置一个配置文件BootstrapImportSelectorConfiguration

    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()));
    		}
    		builder.sources(BootstrapImportSelectorConfiguration.class);

202309152315078415.png

202309152315089006.png
所以等于创建了一个普通的新上下文啦。

bootstrapServiceContext创建新上下文三

SpringApplicationBuilderrun方法:

202309152315096617.png

202309152315105948.png
最终还是调用SpringApplicationrun,但是里面就简单的做了一件事,注册我们的BootstrapImportSelectorConfiguration配置文件,具体我们下篇说吧。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。

阅读全文