SpringBoot运行源码分析:Spring应用上下文准备,java并发编程的艺术和并发编程实战

postProcessApplicationContext( context);//在 context 刷新之前,Appl icat ionContext Init

ial izer 初始化 context

applyInitializers(context);

//通知监听器 context 准备完成,该方法以 上为上下文准备阶段,以下为上下文加载阶段

listeners . contextPrepared(context);//打印日志,启动 Profile

if (this . logStartupInfo)-

logStartupInfo(context . getParent() == nu1l);

logStartupProfileInfo( context);

}

//获得 ConfigurableL istableBeanFactory 并炷册单例对象

ConfigurableL istableBeanFactory beanFactory = context . getBeanFactory();

beanFactory. registerSingleton(“springApplicat ionArguments”, applicationAr

guments);

if (printedBanner != null) {

//注册打印日志对象

beanF actory. registerSingleton(“springBootBanner”, printedBanner);

if (beanFactory instanceof DefaultlistableBeanFactory) {

//没置是否允许覆盖炷册

((DefaultListableBeanFactory) beanFactory)

. setAllowBeanDefinitionOverriding(this . allowBeanDefinitionOverriding);

//获取全部配置源,其中包含 primarySources 和 sources

Set<0bject> sources = getAllSources();

Assert . notEmpty(sources, “Sources must not be empty”);

//将 sources 中的 Bean 加载到 context 中

load(context, sources . toArray(new 0bject[0]));

//遁知监听器 context 加载完成

listeners . contextLoaded(context);

}

通过流程图和具体代码可以看出,在该方法内完成了两步操作:应用上下文的准备和加载。

下面我们针对具体的源代码进行详细讲解。

应用上下文准备阶段

=========

在上下文准备阶段,主要有 3 步操作:对 context 设 置 environment、应用上下文后置处理和 ApplicationContextlnitializer 初始化 context 操作。

首先是对 context 设置 environment,代码和业务操作都很简单。

public void setEnvironment (ConfigurableEnvironment environment) {

//设置 context 的 environment

super. setE

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

nvi ronment( environment);

//设置 context 的 reader 属性的 conditionEvaluator 属性 this.reade

er. settEnvironment(environment) ;

//设置 context 的 scanner 属性的 environment 属性

this. scanner. setEnvi ronment ( envi ronment);

}

随 后 , 便 是 进 行 Spring 应 用 上 下 文 的 后置处理 , 这 一 步 是 通 过postProcessApplicationContext 方法来完成的。

protected void postProcessApplicat ionContext (ConfigurableApplicat ionConEext

context){

f (this. beanNameGenerator != null) {

// 如果 beanNameGenerator 为 null, 则将当前的 beanNameGenerator 按照默认名字进

行注册

context . getBeanFactory(). regi sterSingleton(

Annotat ionConfigUtils .CONF IGURATION BEAN NAME GENERATOR,

this . beanNameGenerator);

esourceLoader 为 null 时, 则根据 context 的类型分别进行 Resourceloader 和 CL

assLoader 的设置

if (this .resourceLoader != null) {

F (context instanceof GenericApplicationContext) {

((GenericApplicationContext) context) . setResourcel oader(this . resource

Loader);

if (context instanceof DefaultResourceLoader) {

( (DefaultResourceLoader) context)

. setClassLoader(this.resourceLoader. getClassLoader());

//如果为 true 则获取并没置转换服务

f (this .addConversionService) {

context . getBeanFactory(). setConversionService(

ApplicationConversionService . getSharedInstance());

}

postProcessApplicationContext 方 法 主 要 完 成 上 下 文 的 后 置 操 作 , 默 认 包 含beanNameGeneratorResourceL oader.ClassL oader 和 ConversionService 的设置。该方法可由子类覆盖实现,以添加更多的操作。

而在此阶段,beanNameGenerator 和 resourceL oader 都为 null,因此只操作了最后-一步的设置转换服务。

最后,在通知监听器 context 准备完成之前,通过 applylnitializers 方法对上下文进行初始化。

所使用的 ApplicationContextInitializer 正是我们在 SpringApplication 初始化阶段设置在itializers 变量中的值,只不过在通过 getlnitializers 方法获取时进行了去重和排序。

protected void applyInitializers(ConfigurableApplicat ionContext context) {

/获取 Appl icat ionContextInitializer 集合并遍历

for (ApplicationContextInitializer initializer : getInitializers()) {

//解析当前 initial izer.实现的 Appl icat ionContextInitializer 的泛型参数

Class<?> requiredType = GenericTypeResolver . resolveTypeArgument(

initializer . getClass(), ApplicationContextInitializer.class);

1 断言判断所需类似是否与 context 类型匹配

Assert. isInstanceOf(requiredType, context, "Unable to call initialize

r.");

// 初始化 context

initializer. initialize(context);

}

}

完成以上操作之后,程序便调用 SpringApplicationRunListeners 的 contextPrepared 方法通知监听器,至此第一阶段的准备操作完成。

应用上下文加载阶段

=========

应用上下文加载阶段包含以下步骤:打印日志和 Profile 的设置、设置是否允许覆盖注册、获取全部配置源、将配置源加载入上下文、通知监控器 contex 加载完成。

首先进入应用上下文加载阶段的操作为打印日志和 Profile 的设置,对此不展开讲解。随后,便是获得 ConfigurableL istableBeanFactory 并注册单例对象,注册的单例对象包含:

ApplicationArguments 和 Banner。 当 BeanFactory 为 DefaultL istableBeanFactory 时,进入设置是否允许覆盖注册的处理逻辑。

此处需注意的是,当进行了 ApplicationArguments 类单例对象的注册之后,也就意味着我们在使用 Spring 应用上下文的过程中可以通过依赖注入来使用该对象。

@Resource

private ApplicationArguments applicat ionArguments;

完成以.上操作后,便进入配置源信息的处理阶段,这一步通过 getAllSources 方法来对配置源信息进行合并操作。

public Set getAllSources() {

Set<0bject> allSources = new LinkedHashSet<>();

if (!CollectionUtils.isEmpty(this . primarySources)) {

allSources.addAll(this.primarySources);

if (!CollectionUtils . isEmpty(this. sources)) {

allSources. addAll(this.sources);

}

}

return Collections . unmodifiableSet(allSources); }以上操作逻辑很简单,如果 Set 集合中不存在 primarySources 配置源或 sources 配置源,则将其添加入 Set 中,同时将 Set 设置为不可修改,并返回。

前面章节已经提到,变量 primarySources 的值 来自 SpringApplication 的构造参数,变量sources 的值来自 setResources 方法。

当获得所有的配置源信息之后,通过 load 方法将配置源信息加载到上下文中,代码如下。

protected void load(ApplicationContext context, Object[] sources) {

/日志打印

BeanDefinitionLoader loader = createBeanDefinitionLoader(

getBeanDefinitionRegistry(context), sources);

f (this. beanNameGenerator != nu1l).

loader. setBeanNameGenerator(this . beanNameGenerator);

if (this.resourceLoader != nu1l) {

loader . setResourceLoader(this . resourceLoader);

if (this. environment != null) {

loader . setEnvironment (this . environment) ;

loader. load();

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值