2023-09-15  阅读(5)
原文作者:王伟王胖胖 原文地址: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配置文件,具体我们下篇说吧。

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


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文