Spring中的refreshContext源码分析

 更新时间:2023年12月31日 09:22:17   作者:唐芬奇  
这篇文章主要介绍了Spring中的refreshContext源码分析,在SpringBoot启动流程中,主要的两个阶段是初始化SpringApplication对象以及SpringApplication.run方法执行的内容,今天主要细讲的是SpringApplication.run中的刷新容器refreshContext方法,需要的朋友可以参考下

前言

在SpringBoot启动流程中,主要的两个阶段是初始化SpringApplication对象以及SpringApplication.run方法执行的内容

今天主要细讲的是SpringApplication.run中的刷新容器refreshContext方法

refreshContext()

还是老办法,先梳理它的大体流程,将不太重要的舍去。

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			...
			// Prepare the bean factory for use in this context.
			//设置beanFacotry 和加载一些特殊bean的处理类,
			prepareBeanFactory(beanFactory);
				// 一些web项目的bean处理类
				postProcessBeanFactory(beanFactory);
				// Invoke factory processors registered as beans in the context.
				//重要,唤醒 BeanFactoryPostProcessor的实现类
				invokeBeanFactoryPostProcessors(beanFactory);
				...
				// Register bean processors that intercept bean creation.
				//重要,将BeanPostProcessor的bean定义注册进来
				registerBeanPostProcessors(beanFactory);
				...
				// Initialize event multicaster for this context.
				//再次创建一个广播器
				initApplicationEventMulticaster();
				...
				// Check for listener beans and register them.
				//注册listener到上述的心广播器中
				registerListeners();
				// Instantiate all remaining (non-lazy-init) singletons.
				//重要,创建单例bean
				finishBeanFactoryInitialization(beanFactory);
				...
		}
	}

那么整体上就分为一下几步

  1. 对beanFacotry进行设置
  2. 对benFactory在做一些定制处理(比如加载一些web容器对bean的处理类)
  3. 唤醒beanFactoryPostProcessor的一些列实现类
  4. 创建一个新广播器
  5. 将Listener加入到这个新广播器中(注意,这的Listener将会比我们上一篇所说的多的多,至于原因 在唤醒那一步里面)
  6. 将所有找到的单例类,都创建处理(这步内容也比较多,对于加载Bean的分析 将新启一篇文章进行说明)

prepareBeanFactory()

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		//添加了一个BeanPostProcessor实例ApplicationContextAwareProcessor
		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		//指定特定依赖的返回结果
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);
		// Register early post-processor for detecting inner beans as ApplicationListeners.
		//添加了一个BeanPostProcessor实例ApplicationListenerDetector
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
		...
	}

老办法 ,逐一分析。

第一步,添加了一个BeanPostProcessor实例ApplicationContextAwareProcessor

  	ApplicationContextAwareProcessor //这个bean处理器就是在实现了
 		EnvironmentAware.class
 		EmbeddedValueResolverAware.class
 		ResourceLoaderAware.class
 		ApplicationEventPublisherAware.class
 		MessageSourceAware.class
 		ApplicationContextAware.class
 		//的类实例化之前唤醒对应的接口方法

指定特定依赖的返回结果添加了一个BeanPostProcessor实例ApplicationListenerDetector

这个实例主要是检查bean是否实现了ApplicationListener,如果实现了就将它添加到监听器集合中

前面我们说了也可以通过spring.factories这个文件添加ApplicationListenr

这里又提供了一种方式,但是这种通过ApplicationListenerDetector来加载的方式 会让listener丢失一部分事件(因为在没有加载Bean之前还有很多事件),如果需要监听非常前面的事件,还是要通过spring.factories这个文件添加

这里都是讲处理类加载进来,并没有执行对应方法。真正访问还在后面,前面只是准备阶段

invokeBeanFactoryPostProcessors()

唤醒所有的BeanFactoryPostProcessor实例 ,这个与下面的registerBeanPostProcessor将会以独立的章节来分析(原因还是那个原因。。。 里面的内容有点多)。

registerBeanPostProcessor()

将BeanPostProcessor实例注册进来

registerListeners()

protected void registerListeners() {
		// Register statically specified listeners first
		//加载老的listener
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}
		//加载新的listenner
		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let post-processors apply to them!
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}
		// Publish early application events now that we finally have a multicaster...
		//发送默认的事件集
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

这一步就是将listener注册到新的广播器中,分步走。

  • 加载老的listener,也就是我们最开始通过spring.factories加载进来的监听器
  • 加载通过ApplicationListenerDetector注册进来的监听器
  • 发送默认事件(就是表明这个时间节点的事件)到监听器中

完成bean的初始化,这个会单独形成一个章节,与getBean流程一起讲解

总结

  1. 准备BeanFacotry
  2. BeanFacotry准备完毕
  3. 对BeanFacotryPostProcessor进行唤醒(因为BeanFactory准备完毕了嘛)
  4. 注册BeanPostProcessor(因为接下来我们要实例化Bean嘛)
  5. 对单例Bean进行实例化

你看,逻辑清晰,前后有因果,一下就把整体流程给理顺了,而且出乎意料的合理。

到此这篇关于Spring中的refreshContext源码分析的文章就介绍到这了,更多相关refreshContext源码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用@JsonFormat的一个坑及解决

    使用@JsonFormat的一个坑及解决

    这篇文章主要介绍了使用@JsonFormat的一个坑及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • 关于spring 扫描不到jar中class文件的原因分析及解决

    关于spring 扫描不到jar中class文件的原因分析及解决

    这篇文章主要介绍了关于spring 扫描不到jar中class文件的原因分析及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Java AWT中常用的三种布局管理器详解

    Java AWT中常用的三种布局管理器详解

    这篇文章主要介绍了Java AWT中常用的三种布局管理器详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • Java File类常用方法与文件过滤器详解

    Java File类常用方法与文件过滤器详解

    Java File类以抽象的方式代表文件名和目录路径名。该类主要用于文件和目录的创建、文件的查找和文件的删除等。File对象代表磁盘中实际存在的文件和目录。本篇文章我们来讲解File类的常用方法与文件过滤器
    2022-04-04
  • Java接收前端请求体的多种方式总结

    Java接收前端请求体的多种方式总结

    这篇文章主要给大家介绍了关于Java接收前端请求体的多种方式,文中通过代码介绍的非常详细,对大家学习或者Java具有一定的参考学习价值,需要的朋友可以参考下
    2023-08-08
  • 深入理解Java中HashCode方法

    深入理解Java中HashCode方法

    这篇文章主要介绍了深入理解Java中HashCode方法,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • java并发容器ConcurrentHashMap深入分析

    java并发容器ConcurrentHashMap深入分析

    这篇文章主要为大家介绍了java并发容器ConcurrentHashMap使用示例及深入分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • 如何在springboot中引入参数校验

    如何在springboot中引入参数校验

    一般我们判断前端传过来的参数,需要对某些值进行判断,是否满足条件,而springboot相关的参数校验注解,可以解决我们这个问题,本文给大家介绍如何在springboot中引入参数校验,感兴趣的朋友一起看看吧
    2023-12-12
  • 手把手教你SpringBoot快速集成Swagger的配置过程

    手把手教你SpringBoot快速集成Swagger的配置过程

    这篇文章主要介绍了手把手教你SpringBoot快速集成Swagger的配置过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • Java分支结构程序设计实例详解

    Java分支结构程序设计实例详解

    这篇文章主要介绍了Java分支结构程序设计例题,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-01-01

最新评论