当前位置: 首页 > article >正文

【Spring源码分析】Spring的启动流程源码解析

阅读此需阅读下面这些博客先
【Spring源码分析】Bean的元数据和一些Spring的工具
【Spring源码分析】BeanFactory系列接口解读
【Spring源码分析】执行流程之非懒加载单例Bean的实例化逻辑
【Spring源码分析】从源码角度去熟悉依赖注入(一)
【Spring源码分析】从源码角度去熟悉依赖注入(二)
【Spring源码分析】@Resource注入的源码解析
【Spring源码分析】循环依赖的底层源码剖析

Spring的启动流程源码解析

  • 一、AnnotationConfigApplicationContext()具体流程
    • reader 构造逻辑
    • scanner 构造逻辑
  • 二、refresh 源码分析
    • prepareRefresh()
    • obtainFreshBeanFactory()
    • !prepareBeanFactory(beanFactory) !
    • postProcessBeanFactory(beanFactory);
    • !invokeBeanFactoryPostProcessors(beanFactory);!
    • registerBeanPostProcessors(beanFactory)
    • initMessageSource()
    • initApplicationEventMulticaster()
    • onRefresh() 和 registerListeners()
    • finishBeanFactoryInitialization(beanFactory)
  • 三、总结

阐述这篇要讲述的内容,这篇主要是去阐述Spring在启动过程中会做哪些事情,具体指示的代码是下面这三行(没直接说AnnotationConfigApplicationContext重载的那个构造,是因为SpringBoot就是用的下三行,所以干脆就这样了):

		AnnotationConfigApplicationContext
				context = new AnnotationConfigApplicationContext();
		context.register(AppConfig.class);
		context.refresh();

那么这篇就主要就是说这三行代码都做了啥,Spring启动流程就是啥,其中 refresh() 方法是主要的,内容也有点多。

一、AnnotationConfigApplicationContext()具体流程

可以说就三步:

  1. 构造 DefaultListableBeanFactory 实例;
    • 调用构造方法首先是先执行的父类构造,父类构造会实例化一个 DefaultListableBeanFactory。
    • 在这里插入图片描述
  2. 实例化 AnnotatedBeanDefinitionReader 实例;
  3. 实例化 ClassPathBeanDefinitionScanner 扫描器。
	public AnnotationConfigApplicationContext() {
		// super(); 这里会构造 BeanFactory
		StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
		// 额外会创建StandardEnvironment
		this.reader = new AnnotatedBeanDefinitionReader(this);
		createAnnotatedBeanDefReader.end();

		// 会填充 Environment 和 ClassLoader 类加载器;
		// 会将 @Component 注解放入到 includeFilter 集合中,扫描的时候筛选出对应的资源好封装成BeanDefinition
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

有必要看一下 AnnotationConfigApplicationContext 关系图:

在这里插入图片描述那有关 BeanFactory 接口的功能呢其实就是调用 beanFactory#对应方法.

reader 构造逻辑

	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
		this(registry, getOrCreateEnvironment(registry));
	}

会去获取一个 StandardEnvironment 对象,然后调用另一个构造方法
在这里插入图片描述

	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		this.registry = registry;
		// 用来解析@Conditional注解的
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		// 注册
		// 这里主要是去设置比较器和是否允许注入的解析器
		// 而后续的后置处理器是等扫描完还会将这些后置处理器拿到然后去放进去,这里的话没用
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

流程也是比较简单,就是构建个 @Conditional 注解的解析器,后续扫描BeanDefinition的候选者用到了;然后就是去向BeanFactory中注入 Order 比较器 AnnotationAwareOrderComparator 和 注入候选者解析器 ContextAnnotationAutowireCandidateResolver

后者那个 ContextAnnotationAutowireCandidateResolver 其实就是在我们@Autowired或者说@Resource注解注入的时候,在通过类型去找Bean的时候,会有一段责任链设计模式的筛选——autowireCandidate 参数值应该为 true->泛型判断->@Qualifier 解析,不知道还记不记得,不记得没关系,不影响流程的阅读。

随后会注入一些 BeanPostProcessor 和 BeanFactoryPostProcessor,这里是还未实例化的,是注入到 BeanDefinitionMapBeanDefinitionNames 里的注入。

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		// 注册ConfigurationClassPostProcessor类型的BeanDefinition
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// 注册AutowiredAnnotationBeanPostProcessor类型的BeanDefinition
		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// 注册CommonAnnotationBeanPostProcessor类型的BeanDefinition
		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// 注册EventListenerMethodProcessor类型的BeanDefinition,用来处理@EventListener注解的
		// 处理 @EventListener 会遍历所有的 beanNames 对应的Class,只要是单例就行,是懒加载也会解析为对应的ApplicationListener
		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}

		// 注册DefaultEventListenerFactory类型的BeanDefinition,用来处理@EventListener注解的
		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

  • 首先是注入了 ConfigurationClassPostProcessor,它类的结构如下,后面扫描要用:
    • 在这里插入图片描述
  • 然后是注入 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor,我们的@Value、@Resource、@Autowired、@Qualified、@PreDestroy、@PostConstruct…等注解作用都是靠它俩完成的
  • 随后注入 EventListenerMethodProcessor ,它是用来 @EventListener 注解的,主要解析对象是 beanDefinitionNames 里存在滴;
  • 随后注入 DefaultEventListenerFactory 它是用来将 @EventListener 修饰的方法构建成 ApplicationListener 实例,然后放入到监听集中。

scanner 构造逻辑

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
										  Environment environment, @Nullable ResourceLoader resourceLoader) {
		this.registry = registry;

		if (useDefaultFilters) {
			registerDefaultFilters();
		}
		setEnvironment(environment);
		setResourceLoader(resourceLoader);
	}

在这里插入图片描述

也没做啥就是将 @Component 注解放入进 includeFilters 集合中,后续筛选候选者 BeanDefinition 用,然后把环境对象和资源加载器构建一手,就后续扫描资源用的。

看完 AnnotationConfigApplicationContext 的无参构造可以知道:
它无非就是去构建后续 register、refresh和扫描需要的环境

context.register 其实没做啥,就是将我们上面写的 AppConfig 直接通过 reader 将其对应的BeanDefinition和beanName容器中就是了。

二、refresh 源码分析

这个好长,我只能一个方法一个方法解析了,如果不愿看的可以直接跳到总结看流程图。

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			// 一些标志位和验证,咱别管
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 这里会判断能否刷新,并且返回一个BeanFactory, 刷新不代表完全情况,主要是先执行Bean的销毁,然后重新生成一个BeanFactory,再在接下来的步骤中重新去扫描等等
			// 对于Spring来说,对于AnnotationConfigApplicationContext来说,不允许下一次refresh也是在这个阶段进行的
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 准备BeanFactory
			// 1. 设置BeanFactory的类加载器、SpringEL表达式解析器、类型转化注册器
			// 2. 添加三个BeanPostProcessor,注意是具体的BeanPostProcessor实例对象
			// 3. 记录ignoreDependencyInterface
			// 4. 记录ResolvableDependency
			// 5. 添加三个单例Bean
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 子类来设置一下BeanFactory
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

				// Invoke factory processors registered as beans in the context.
				// BeanFactory准备好了之后,执行BeanFactoryPostProcessor,开始对BeanFactory进行处理
				// 默认情况下:
				// 此时beanFactory的beanDefinitionMap中有6个BeanDefinition,5个基础BeanDefinition+AppConfig的BeanDefinition
				// 而这6个中只有一个BeanFactoryPostProcessor:ConfigurationClassPostProcessor
				// 这里会执行ConfigurationClassPostProcessor进行@Component的扫描,扫描得到BeanDefinition,并注册到beanFactory中
				// 注意:扫描的过程中可能又会扫描出其他的BeanFactoryPostProcessor,那么这些BeanFactoryPostProcessor也得在这一步执行
				invokeBeanFactoryPostProcessors(beanFactory);  // scanner.scan()

				// Register bean processors that intercept bean creation.
				// 将扫描到的BeanPostProcessors实例化并排序,并添加到BeanFactory的beanPostProcessors属性中去
				registerBeanPostProcessors(beanFactory);

				beanPostProcess.end();

				// Initialize message source for this context.
				// 设置ApplicationContext的MessageSource,要么是用户设置的,要么是DelegatingMessageSource
				initMessageSource();

				// Initialize event multicaster for this context.
				// 设置ApplicationContext的applicationEventMulticaster,要么是用户设置的,要么是SimpleApplicationEventMulticaster
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 给子类的模板方法
				// Spring啥也没干,MVC倒是重写了,给其他的模板方法
				onRefresh();

				// Check for listener beans and register them.
				// 把定义的ApplicationListener的Bean对象,设置到ApplicationContext中去,并执行在此之前所发布的事件
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 实例化所有非懒加载的单例bean
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

prepareRefresh()

一些标志位设置和验证啥的,跟咱开发关系不大,跳过~

obtainFreshBeanFactory()

这个方法是去得到 BeanFactory,我们之前阐述了,在 AnnotationConfigApplicationContext 的父类的无参构造中会构建一个 DefaultListableBeanFactory,这里就是将这个返回。

在这里插入图片描述在这里插入图片描述

但这里还需要注意的是 refresh 方法不能重复调用,就是在这里进行判断的。

在这里插入图片描述
内部封装了一个 refreshed 的标志为,类型是 AtomicBoolean 类型的,这里会通过 CAS 判断设置,如果已经是true了会抛出异常,表示不允许重复进行 refresh。
在这里插入图片描述

!prepareBeanFactory(beanFactory) !

这个方法做了挺多事的,主要是对 BeanFactory 的初始化,但是在我们之前都有遇到,它何时注入的呢?下面看看:

  1. 注入类加载器、Spel 解析器、类型转化器(在咱Bean生命周期createBean的第一步就是去尝试使用类加载器对类进行加载;在注入解析@Value的时候针对#{}就是Spel解析器在发挥作用;类型转化器在找到注入实例不就开始用类型转化器进行转化了)。
    在这里插入图片描述
  2. 添加一个 ApplicationContextAwareProcecssor 实例到 BeanFactory 容器中(它就是针对那些Aware注入嘛,在生命周期之初始化前会遍历BeanPostProcessor那里),可以发现它是第一个填充到 BeanFactory 容器中的 BeanPostProcessor

在这里插入图片描述

  1. 向 ignoreDependecyInterfaces 中添加点东西,这个无所谓的,这个是Spring提供的那种ByName/ByType的注入方式,前面参数 populateBean 一 的时候有说过,开发又不用不阐述了,就是说这里面的setter的话就不会进行注入了。
    在这里插入图片描述
  2. 注入一些Bean,表示已经解析过了。这个在我们去根据类型找Bean的时候,就是会拿注入的类型和这些去比对,如果比对成功就直接注入这里的 Bean(如果想不起来了,去看属性注入二,我阐述过了)。

在这里插入图片描述

  1. ApplicationListenerDetector 这个事件监听器的检测BeanPostProcessor。它主要是在Bean初始化后那个时候去判断一下是否是单例且是否实现了ApplicationListener接口,如果是就放入到applicationListeners集合中。可以说这是Spring启动阶段放入到BeanFactory中的第二个BeanPostProcessor,用于检测容器中的ApplicationListener。
    在这里插入图片描述在这里插入图片描述
  2. 将环境对象放到单例池里(这属于手动添加单例池)
    在这里插入图片描述

postProcessBeanFactory(beanFactory);

Spring 这个方法没有实现,这是一个模板方法,用于其他接入Spring的,用来填充BeanFactory的。

!invokeBeanFactoryPostProcessors(beanFactory);!

代码太多,这里就阐述个流程,其中如何解析的配置也是在这个方法中,其中在解析@ComponentScan的时候就会进行扫描,我下篇博客阐述。
首先里面是用的 BeanFactoryPostProcessor ,准确点说是它的子类 BeanDefinitionRegistryPostProcessor。前面我们阐述过一些 BeanPostProcessor,那是用来处理 Bean 的后置处理器,那这个 BeanFactoryBeanProcessor 就是 BeanFactory 的后置处理器。(阐述这个是为了你们若是根据这个博客去看源码的话不会懵,还有就是前面在构造reader的时候注入了 ConfigurationClassPostProcessor,在此之前就注入了这么个BeanFactoryPostProcessor)

下面直接阐述流程:

  • 解析配置类
    • 解析 @ComponentScan,扫描得到BeanDefinition并注册;
    • 解析 @Bean、@Import等注解得到BeanDefinition并注册;
    • 详细下篇博客阐述;
  • 执行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry()
  • 执行 BeanDefinitionRegistryPostProcessor#postProcessBeanFactory()

说白了就是解析注解后注册BeanDefinition。

registerBeanPostProcessors(beanFactory)

这里就是注册BeanPostProcessor到单例池中,然后添加到 beanPostProcessors 集合中,说是排了序,但感觉排不排一个样。就是 @PriorityOrdered > @Ordered > 啥都没有的。说是这样说,但我感觉Spring中的BeanPostProcessor没啥顺序可言,以下是Spring的顺序,大伙看看就行:

在这里插入图片描述其中那个AsyncAnnotationBeanPostProcessor那个是因为我开始加了@EnableAsync注解忘记去掉了。

initMessageSource()

就是设置 ApplicationContext 的 MessageSource,没啥好说的。

initApplicationEventMulticaster()

初始化事件转播器,默认是 SimpleApplicationEventMulticaster,如果自己构建了并且放入了容器,那就用咱的,但谁没事写这玩意啊。

在这里插入图片描述

onRefresh() 和 registerListeners()

onRefresh 是模版方法,Spring啥也没干;
registerListeners 的作用是把定义好的 ApplicationListener 的Bean对象注入到ApplicationContext中,但是Spring本质啥也没干,因为没有。

finishBeanFactoryInitialization(beanFactory)

这就核心来了,实例化所有的非懒加载的单例Bean。
前面博客讲述了这个的主要流程。

三、总结

可以看流程图:
https://www.processon.com/view/link/5f60a7d71e08531edf26a919

但是感觉看流程图挺累的,还是简单阐述一下吧(大概流程哈,不可能详细阐述):

  • 构建个DefaultBeanFactory注入进去;
  • 构建环境:reader、scanner、一些BeanPostProcessor这些;
  • 通过 ConfigurationClassPostProcessor 去扫描配置类;
  • 然后去实例化容器里的 BeanPostProcessor 到 beanPostProcessors 集合中;
  • 构建事件传播器;
  • 实例化非懒加载单例Bean到单例池中。

http://www.kler.cn/a/234534.html

相关文章:

  • 多进程/线程并发服务器
  • 【FFmpeg】FFmpeg 函数简介 ③ ( 编解码相关函数 | FFmpeg 源码地址 | FFmpeg 解码器相关 结构体 和 函数 )
  • C++ 编程基础(6)作用域 | 6.3、类作用域
  • 01:(手撸HAL+CubeMX)时钟篇
  • Lucene 和 Elasticsearch 中更好的二进制量化 (BBQ)
  • ISAAC SIM踩坑记录--ubuntu 22.04操作系统安装
  • [C#]无法获取源 https://api.nuge t.org/v3-index存储签名信息解决方法
  • 有哪些方法可以配置并发服务器?
  • 软考 系统分析师系列知识点之信息系统战略规划方法(6)
  • ElementUI鼠标拖动没列宽度
  • C++学习笔记——typedef和using
  • 【机器学习300问】23、什么是主动学习?
  • 基于Java实现Socket文件传输代码详解
  • 算法学习系列(三十二):背包问题
  • 笔记——asp.net core 中的 REST
  • 【iOS操作系统——讲解】
  • leetcode-206-翻转链表
  • 【Jenkins】Jenkins关闭Jenkins关闭、重启
  • LeetCode---383周赛
  • 学了很多知识,没多久就忘光了,怎么办?
  • 力扣刷题之旅:进阶篇(六)—— 图论与最短路径问题
  • 网络的基本概念和socket编程
  • java 类加载过程
  • Vulnhub靶机:hacksudo-search
  • Java实现数据可视化的智慧河南大屏 JAVA+Vue+SpringBoot+MySQL
  • 踩坑实录(Second Day)