交流
商城
MCN
登入
注册
首页
提问
分享
讨论
建议
公告
动态
发表新帖
发表新帖
spring cloud 第1 章:父上下文加载spring.cloud.bootstrap.enabled
分享
未结
0
1108
李延
LV6
2021-06-09
悬赏:20积分
# 入口 当我们引入cloud的包后,发现多了这3个jar包  我们知道springboot会自动加载spring.factories下配置的内容。我们在ontext的包中找到了下面的内容:  这里加载了3个listener。我们关注BootstrapApplicationListener这个对象 # BootstrapApplicationListener 这个类继承自ApplicationListener<ApplicationEnvironmentPreparedEvent>。根据我们对springboot的分析。我们知道这个listener会在environment创建完成时出发。 而我们知道配置文件的加载也是在这个事件中触发的所以我们需要具体看以下它们的先后顺序: 配置文件加载:EnvironmentPostProcessorApplicationListener  BootstrapApplicationListener加载:  我们看到BootstrapApplicationListener的优先度是高于配置文件的加载的。所有在出发BootstrapApplicationListener时,配置文件还没有被加载进来。 ## onApplicationEvent ```java @Override public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { ConfigurableEnvironment environment = event.getEnvironment(); //检查是否开启了bootstrapEnabled if (!bootstrapEnabled(environment) && !useLegacyProcessing(environment)) { return; } // don't listen to events in a bootstrap context //检查是否已经加载过了,如果已经加载了,就直接返回 if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) { return; } ConfigurableApplicationContext context = null; //虎获取bootstrap上下文名称。默认bootstrap String configName = environment.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}"); // 通过SpringApplication上下文获取initializer,如果是ParentContextApplicationContextInitializer,则为其设置父上下文 for (ApplicationContextInitializer<?> initializer : event.getSpringApplication().getInitializers()) { if (initializer instanceof ParentContextApplicationContextInitializer) { context = findBootstrapContext((ParentContextApplicationContextInitializer) initializer, configName); } } //创建父上下问,并执行run方法 if (context == null) { context = bootstrapServiceContext(environment, event.getSpringApplication(), configName); event.getSpringApplication().addListeners(new CloseContextOnFailureApplicationListener(context)); } //将父上下文中的initializer添加到springApplication上下文中。 apply(context, event.getSpringApplication(), environment); } ``` 通过上面注解我们看见在这里创建了一个父上下问并执行了run方法。我们下面主要看一下这个上下文都加载了什么内容。 # bootstrapServiceContext 创建父上下文并执行。 ```java 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<>(); bootstrapMap.put("spring.config.name", configName); // if an app (or test) uses spring.main.web-application-type=reactive, bootstrap // will fail // force the environment to use none, because if though it is set below in the // builder // the environment overrides it 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); } // 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) { // gh_425: // SpringApplication cannot deduce the MainApplicationClass here // if it is booted from SpringBootServletInitializer due to the // absense of the "main" method in stackTraces. // But luckily this method's second parameter "application" here // carries the real MainApplicationClass which has been explicitly // set by SpringBootServletInitializer itself already. builder.main(application.getMainApplicationClass()); } if (environment.getPropertySources().contains("refreshArgs")) { // If we are doing a context refresh, really we only want to refresh the // Environment, and there are some toxic listeners (like the // LoggingApplicationListener) that affect global static state, so we need a // way to switch those off. builderApplication.setListeners(filterListeners(builderApplication.getListeners())); } builder.sources(BootstrapImportSelectorConfiguration.class); final ConfigurableApplicationContext context = builder.run(); // gh-214 using spring.application.name=bootstrap to set the context id via // `ContextIdApplicationContextInitializer` prevents apps from getting the actual // spring.application.name // during the bootstrap phase. context.setId("bootstrap"); // Make the bootstrap context a parent of the app context addAncestorInitializer(application, context); // It only has properties in it now that we don't want in the parent so remove // it (and it will be added back later) bootstrapProperties.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME); mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties); return context; } ``` 上面代码中我们看到对于父上下文中environment对象是一个新创建的StandardEnvironment。同时设置了下面两个默认属性:  所有父上下文会读取bootstrap的文件。同时创建的是一个非web的环境。 同时source设置的是: ```java builder.sources(BootstrapImportSelectorConfiguration.class); ``` 在BootstrapImportSelectorConfiguration上没有自动装配的注解。所以我们我们自动装配的内容不会被加载。而是加载BootstrapImportSelectorConfiguration的内容。 ## mergeDefaultProperties 在执行完父上下文后,只想此方法,将两个environment对象进行合并,这样在我们启动的上下文中就可以获取到父上下文中加载的内容。
回帖
消灭零回复
提交回复
热议榜
java 相关知识分享
8
好的程序员与不好的程序员
6
写给工程师的十条精进原则
5
spring boot以jar包运行配置的logback日志文件没生成
5
一步一步分析SpringBoot启动源码(一)
5
MockMvc测试
5
【吐槽向】是不是有个吐槽的板块比较好玩
4
logstash jdbc同步mysql多表数据到elasticsearch
3
IntelliJ IDEA 优质License Server
3
.gitignore忽略规则
3
SpringBoot启动源码分析
3
一步一步分析SpringBoot启动源码(三)
3
2
一步一步分析SpringBoot启动源码(二)
2
积分不够将无法发表新帖
2
官方产品
Meta-Boot - 基于MCN
MCN - 快速构建SpringBoot应用
微信扫码关注公众号