Sping IOC 源码剖析

目录

  • 0.看源码的方式
  • 1.Spring IOC初始化的主体流程
    • 1.1.Spring IOC的容器体系
    • 1.2.Bean生命周期关键时机点
      • 1.2.1.Bean生命周期图解
      • 1.2.2.BeanDefinition结构
      • 1.2.3.Bean⽣命周期关键时机点断点分析
    • 1.3.Spring IOC初始化主流程
  • 2.BeanFactory创建流程
    • 2.1 获取BeanFactory⼦流程
    • 2.2.BeanDefine加载解析及注册子流程
  • 3.Bean创建流程
  • 4.lazy-init加载原理
  • 5.Spring IOC循环依赖问题
    • 5.1.循环依赖是什么
    • 5.2.循环依赖处理机制
  • 6.注意事项

0.看源码的方式

  • 好处:提高培养代码架构思维、深入理解框架
  • 原则:
    • 定焦原则:抓主线
    • 宏观原则:站在上帝视角,关注源码结构和业务流程(淡化具体某条代码的编写细节)
  • 读源码的方法和技巧
    • 断点(观察调用栈)
    • 反调(Find Useages)
    • 经验(Spring 框架中doXXX,做具体处理的地方)
  • Spring源码构建
    • 参考spring-framework-5.1.x 源码编译 环境搭建 [ idea:2020.1 ]
    • 下载源码(github)
    • 安装gradle5.6.3(类似maven)、idea2019.1(或以上)、jdk11.0.5
    • 导入(耗费一定时间)
    • 编译工程(顺序:core-oxm-context-beans-aspects-aop)
      • 工程->task->compileTestJava

1.Spring IOC初始化的主体流程

1.1.Spring IOC的容器体系

  • BeanFactory:顶级容器接口类,定义了所有IOC容器必须遵从的一套原则
    • ApplicationContext:增加额外的功能
      • ClassPathXmlApplicationContext:包含解析xml等一系列内容
      • AnnocationConfigApplicationContext:包含解析注解等一系列内容
    • …(BeanFactory其他子接口/实现类)

1.2.Bean生命周期关键时机点

1.2.1.Bean生命周期图解

比如通过反射实例化对象

prototype
singleton
销毁
销毁
第1步:实例化Bean
第2步:设置属性值
第3步:调用BeanNameAware的SetBeanName方法
第4步:调用BeanFactoryAware的setBeanFactory方法
第5步:调用ApplicationContextAware的setAppliactionContext方法
第6步:调用BeanPostProcessor的预初始化方法
第7步:调用InitializingBean的afterPropertiesSet方法
第8步:调用定制的初始化方法init-method
第9步:调用BeanPostProcessor的后初始化方法
将准备就绪的Bean交给调用者
Spring缓存池中准备就绪的Bean
调用DisposableBean的destory方法
调用destory-method属性配置的销毁方法
Bean生命周期的整个执行过程描述:
1.根据配置情况调用Bean构造方法或工厂方法实例化Bean
2.利用依赖注入完成Bean中所有属性值的配置注入
3.如果Bean实现了BeanNameAware接口,则Spring调用Bean的setBeanName()方法传入当前Bean的id值
4.如果Bean实现了BeanFactoryAware接口,则Spring调用setBeanFactory()方法传入当前工厂实例的引用
5.如果Bean实现了ApplicationContextAware接口,则Spring调用setApplicationContext()方法传入当前ApplicationContext实例的引用
6.<如果BeanPostProcessor和Bean关联,则Spring将调用该接口的预初始化方法postProcessBeforeInitialzation()对Bean进行加工操作,此处非常重要,Spring的AOP就是利用它实现的>
7.如果Bean实现了InitializingBean接口,则Spring将调用afterPropertiesSet()方法
8.如果在配置文件中通过init-method属性指定了初始化方法,则调用该初始化方法
9.<如果BeanPostProcessor和Bean关联,则Spring将调用该接口的初始化方法postProcessAfterInitialzation(),此时,Bean已经可以被应用系统使用了>
10.如果在<bean>中指定了该Bean的作用范围scope="singleton",则该Bean将放入Spring IOC的缓存池中,将触发Spring 对该Bean的生命周期管理;如果在<bean>中指定了该属性的作用范围scope="prototype",则将该Bean交给调用者
11.如果Bean实现了DisposableBean接口,则Spring会调用destory()方法将Spring中的Bean销毁;如果在配置文件中通过destory-method属性指定了Bean的销毁方法,则Spring将调用该方法对Bean进行销毁
<注意:Spring为Bean提供了细致全面的生命周期过程,通过实现特定的接口或bean的属性值设置,都可以对Bean的生命周期过程产生影响,虽然可以随意配置bean的属性值,但是建议不要过多的使用Bean实现接口,因为这样会导致代码和Spring的聚合过于紧密>

1.2.2.BeanDefinition结构

Sping IOC 源码剖析_第1张图片

1.2.3.Bean⽣命周期关键时机点断点分析

  • 思路:创建⼀个类 LagouBean ,让其实现⼏个特殊的接⼝,并分别在接⼝实现的构造器、接⼝⽅法中
    断点,观察线程调⽤栈,分析出 Bean 对象创建和管理关键点的触发时机。
  • LagouBean
import org.springframework.beans.factory.InitializingBean;

public class LagouBean implements InitializingBean {

	private Integer id;
	private String message;

	public LagouBean() {
		System.out.println("构造函数...");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("初始化....");
	}
}

  • BeanPostProcessor 接⼝实现类
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * @Author 应癫
 * @create 2019/12/3 16:59
 */
public class MyBeanPostProcessor implements BeanPostProcessor {

	public MyBeanPostProcessor() {

		System.out.println("BeanPostProcessor 实现类构造函数...");
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if("lagouBean".equals(beanName)) {
			System.out.println("BeanPostProcessor 实现类 postProcessBeforeInitialization 方法被调用中......");
		}
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if("lagouBean".equals(beanName)) {
			System.out.println("BeanPostProcessor 实现类 postProcessAfterInitialization 方法被调用中......");
		}
		return bean;
	}
}
  • BeanFactoryPostProcessor 接⼝实现类
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

/**
 * @Author 应癫
 * @create 2019/12/3 16:56
 */
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	public MyBeanFactoryPostProcessor() {

		System.out.println("BeanFactoryPostProcessor的实现类构造函数...");
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("BeanFactoryPostProcessor的实现方法调用中......");
	}
}
  • applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="
	    http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
">

	<bean id="lagouBean" class="LagouBean"></bean>

	<bean id="myBeanFactoryPostProcessor" class="MyBeanFactoryPostProcessor"/>
	<bean id="myBeanPostProcessor" class="MyBeanPostProcessor"/>

</beans>
  • IoC 容器源码分析⽤例
	@Test
	public void testGetBean(){
		// ApplicationContext是容器的高级接口,BeanFactory(顶级容器/根容器,规范了/定义了容器的基础行为)
		// 叫做单例池,singletonObjects,容器是一组组件和过程的集合,包括BeanFactory、单例池、BeanPostProcessor等以及之间的协作流程)

		// 反向观察bean的调用,通过debug查看调用栈
		// bean对象的构造方法、初始化方法、 bean后置处理器before/after方法: org.springframework.context.support.AbstractApplicationContext#refresh#finishBeanFactoryInitialization
		// beanFactory后置处理器构造方法、postProcessBeanFactory方法:org.springframework.context.support.AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors
		// bean后置处理器构造方法: org.springframework.context.support.AbstractApplicationContext#refresh#registerBeanPostProcessors
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		LagouBean lagouBean = (LagouBean) applicationContext.getBean("lagouBean");
		System.out.println(lagouBean);
	}
  • (1) 分析 Bean 的创建是在容器初始化时还是在 getBean 时
    Sping IOC 源码剖析_第2张图片
    所以:未设置延迟加载的前提下,Bean 的创建是在容器初始化过程中完成的

  • (2)分析构造函数调⽤情况
    Sping IOC 源码剖析_第3张图片
    通过如上观察,我们发现构造函数的调⽤时机在AbstractApplicationContext类refresh⽅法的
    finishBeanFactoryInitialization(beanFactory)处;

  • (3)分析 InitializingBean 之 afterPropertiesSet 初始化⽅法调⽤情况观察
    InitializingBean中afterPropertiesSet ⽅法的调⽤时机也是在AbstractApplicationContext类refresh⽅法的finishBeanFactoryInitialization(beanFactory);

  • (4)分析BeanFactoryPostProcessor 初始化和调⽤情况
    分别在构造函数、postProcessBeanFactory ⽅法处打断点,观察调⽤栈,发现
    BeanFactoryPostProcessor 初始化在AbstractApplicationContext类refresh⽅法的
    invokeBeanFactoryPostProcessors(beanFactory);
    postProcessBeanFactory 调用
    在AbstractApplicationContext类refresh⽅法的
    invokeBeanFactoryPostProcessors(beanFactory);

  • (5)分析 BeanPostProcessor 初始化和调⽤情况
    分别在构造函数、postProcessBeanFactory ⽅法处打断点,观察调⽤栈,发现
    BeanPostProcessor 初始化在AbstractApplicationContext类refresh⽅法的
    registerBeanPostProcessors(beanFactory);
    postProcessBeforeInitialization 调用在AbstractApplicationContext类refresh⽅法的
    finishBeanFactoryInitialization(beanFactory);
    postProcessAfterInitialization 调用在AbstractApplicationContext类refresh⽅法的
    finishBeanFactoryInitialization(beanFactory);

  • 总结
    根据上⾯的调试分析,我们发现 Bean对象创建的⼏个关键时机点代码层级的调⽤都在AbstractApplicationContext 类 的 refresh ⽅法中,可⻅这个⽅法对于Spring IoC 容器初始化来说相当关键,汇总如下:

关键点 触发代码
构造器 refresh#finishBeanFactoryInitialization(beanFactory)
BeanFactoryPostProcessor 初始化 refresh#invokeBeanFactoryPostProcessors(beanFactory)
BeanFactoryPostProcessor ⽅法调用 refresh#invokeBeanFactoryPostProcessors(beanFactory)
BeanPostProcessor 初始化 registerBeanPostProcessors(beanFactory)
BeanPostProcessor ⽅法调⽤ refresh#finishBeanFactoryInitialization(beanFactory)

1.3.Spring IOC初始化主流程

  • 由上分析可知,Spring IoC 容器初始化的关键环节就在 AbstractApplicationContext#refresh() 方法中,我们查看 refresh 方法来俯瞰容器创建的主体流程,主体流程下的具体⼦流程我们后⾯再来讨论。
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			/*第一步:刷新前的预处理
				表示在真正做refresh操作之前需要准备做的事情;
				设置Spring容器的启动时间
				开启活跃状态、撤销关闭状态
				验证环境信息里一些必须存在的属性等
			 */
			prepareRefresh();

			/* 第二步:Tell the subclass to refresh the internal bean factory.
			   获取BeanFactory;默认实现是DefaultListableFactory
			   加载BeanDefition 并注册到 BeanDefitionRegistry
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 第三步:BeanFactory的预准备工作(BeanFactory进行一些设置,比如context的类加载器等)
			prepareBeanFactory(beanFactory);

			try {
				// 第四步:BeanFactory准备⼯作完成后进⾏的后置处理⼯作
				postProcessBeanFactory(beanFactory);

				// 第五步:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
				invokeBeanFactoryPostProcessors(beanFactory);

				// 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执
				registerBeanPostProcessors(beanFactory);

				// 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
				initMessageSource();

				// 第⼋步:初始化事件派发器
				initApplicationEventMulticaster();

				// 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
				onRefresh();

				// 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器bean
				registerListeners();

				/*
				第⼗⼀步:
				初始化所有剩下的⾮懒加载的单例bean
				初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
				填充属性
				初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)
				调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处
				*/
				finishBeanFactoryInitialization(beanFactory);

				/*
				第⼗⼆步:
				完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事
				件 (ContextRefreshedEvent)
				*/
				finishRefresh();
			}
	...
	}
}

2.BeanFactory创建流程

2.1 获取BeanFactory⼦流程

时序图如下
Sping IOC 源码剖析_第4张图片

2.2.BeanDefine加载解析及注册子流程

  • (1)该⼦流程涉及到如下⼏个关键步骤
    • Resource定位:指对BeanDefinition的资源定位过程。通俗讲就是找到定义Javabean信息的XML⽂件,并将其封装成Resource对象。
    • BeanDefinition载⼊ :把⽤户定义好的Javabean表示为IoC容器内部的数据结构,这个容器内部的数据结构就是BeanDefinition。
    • 注册BeanDefinition到 IoC 容器
  • (2)过程分析
    • Step 1:⼦流程⼊⼝在 AbstractRefreshableApplicationContext#refreshBeanFactory ⽅法中
      Sping IOC 源码剖析_第5张图片

    • Step 2:依次调⽤多个类的 loadBeanDefinitions ⽅法 —> AbstractXmlApplicationContext —>AbstractBeanDefinitionReader —> XmlBeanDefinitionReader ⼀直执⾏到XmlBeanDefinitionReader 的 doLoadBeanDefinitions ⽅法
      Sping IOC 源码剖析_第6张图片

    • Step 3:我们重点观察XmlBeanDefinitionReader 类的 registerBeanDefinitions ⽅法,期间产⽣了多次重载调⽤,我们定位到最后⼀个在这里插入图片描述
      此处我们关注两个地⽅:⼀个createRederContext⽅法,⼀个是DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions⽅法,先进⼊createRederContext ⽅法看看
      Sping IOC 源码剖析_第7张图片
      我们可以看到,此处 Spring ⾸先完成了 NamespaceHandlerResolver 的初始化。
      我们再进⼊ registerBeanDefinitions ⽅法中追踪,调⽤了
      DefaultBeanDefinitionDocumentReader#registerBeanDefinitions ⽅法
      在这里插入图片描述
      进⼊ doRegisterBeanDefinitions ⽅法
      Sping IOC 源码剖析_第8张图片
      进⼊ parseBeanDefinitions ⽅法
      Sping IOC 源码剖析_第9张图片
      进⼊ parseDefaultElement ⽅法
      Sping IOC 源码剖析_第10张图片
      进⼊ processBeanDefinition ⽅法
      Sping IOC 源码剖析_第11张图片
      ⾄此,注册流程结束,我们发现,所谓的注册就是把封装的 XML 中定义的 Bean信息封装为BeanDefinition 对象之后放⼊⼀个Map中,BeanFactory 是以 Map 的结构组织这些 BeanDefinition的。
      在这里插入图片描述
      可以在DefaultListableBeanFactory中看到此Map的定义
      private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);

    • 时序图
      Sping IOC 源码剖析_第12张图片

3.Bean创建流程

  • 通过最开始的关键时机点分析,我们知道Bean创建⼦流程⼊⼝在AbstractApplicationContext#refresh()⽅法的finishBeanFactoryInitialization(beanFactory) 处
    Sping IOC 源码剖析_第13张图片
  • 进⼊finishBeanFactoryInitialization
    在这里插入图片描述
  • 继续进⼊DefaultListableBeanFactory类的preInstantiateSingletons⽅法,我们找到下⾯部分的代码,看到⼯⼚Bean或者普通Bean,最终都是通过getBean的⽅法获取实例
    Sping IOC 源码剖析_第14张图片
  • 继续跟踪下去,我们进⼊到了AbstractBeanFactory类的doGetBean⽅法,这个⽅法中的代码很多,我们直接找到核⼼部分
    Sping IOC 源码剖析_第15张图片
  • 接着进⼊到AbstractAutowireCapableBeanFactory类的⽅法,找到以下代码部分
    Sping IOC 源码剖析_第16张图片
  • 进⼊doCreateBean⽅法看看,该⽅法我们关注两块重点区域
    • 创建Bean实例,此时尚未设置属性
      在这里插入图片描述
    • 给Bean填充属性,调⽤初始化⽅法,应⽤BeanPostProcessor后置处理器
      Sping IOC 源码剖析_第17张图片

4.lazy-init加载原理

  • lazy-init 延迟加载机制分析
    普通 Bean 的初始化是在容器启动初始化阶段执⾏的,⽽被lazy-init=true修饰的 bean 则是在从容器⾥第⼀次进⾏context.getBean() 时进⾏触发。Spring 启动的时候会把所有bean信息(包括XML和注解)解析转化成Spring能够识别的BeanDefinition并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个BeanDefinition 进⾏处理,如果是懒加载的则在容器初始化阶段不处理,其他的则在容器初始化阶段进⾏初始化并依赖注⼊。
@Override
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// 触发所有非懒加载单例bean初始化
		for (String beanName : beanNames) {
			// 获取bean定义
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 判断是否是懒加载bean,如果是单例的并且不是懒加载的则在容器创建时初始化
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// 判断是否是FactoryBean
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					/**
					 *如果是普通bean则进⾏初始化并依赖注⼊,此 getBean(beanName)接下来触发的逻辑
					 * 和懒加载时 context.getBean("beanName") 所触发的逻辑是⼀样的
					 */
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

  • 总结
    • 对于被修饰为lazy-init的bean Spring 容器初始化阶段不会进⾏ init 并且依赖注⼊,当第⼀次进⾏getBean时候才进⾏初始化并依赖注⼊
    • 对于⾮懒加载的bean,getBean的时候会从缓存⾥头获取,因为容器初始化阶段 Bean 已经初始化完成并缓存了起来

5.Spring IOC循环依赖问题

5.1.循环依赖是什么

  • 循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如A依赖于B,B依赖于C,C⼜依赖于A。
依赖
依赖
依赖
A
B
C

注意,这⾥不是函数的循环调⽤,是对象的相互依赖关系。循环调⽤其实就是⼀个死循环,除⾮有终结条件。

  • Spring中循环依赖场景有:
    • 构造器的循环依赖(构造器注⼊)
    • Field 属性的循环依赖(set注⼊)
      其中,构造器的循环依赖问题⽆法解决,只能拋出BeanCurrentlyInCreationException 异常,在解决属性循环依赖时,spring采⽤的是提前暴露对象的⽅法。

5.2.循环依赖处理机制

  • 单例 bean 构造器参数循环依赖(⽆法解决)
  • prototype 原型 bean循环依赖(⽆法解决)
    对于prototype 原型bean的初始化过程中不论是通过构造器参数循环依赖还是通过setXxx⽅法产⽣循环依赖,Spring都 会直接报错处理。
    • AbstractBeanFactory.doGetBean()⽅法:
if (isPrototypeCurrentlyInCreation(beanName)) {
	throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
		Object curVal = this.prototypesCurrentlyInCreation.get();
		return (curVal != null &&
				(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
	}

在获取bean之前如果这个原型bean正在被创建则直接抛出异常。原型bean在创建之前会进⾏标记这个beanName正在被创建,等创建结束之后会删除标记

	else if (mbd.isPrototype()) {
			// It's a prototype -> create a new instance.
		Object prototypeInstance = null;
		try {
			beforePrototypeCreation(beanName);
			prototypeInstance = createBean(beanName, mbd, args);
		}
		finally {
			afterPrototypeCreation(beanName);
		}
		bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

总结:Spring 不⽀持原型 bean 的循环依赖。

  • 单例bean通过setXxx或者@Autowired进⾏循环依赖
    • Spring 的循环依赖的理论依据基于 Java 的引⽤传递,当获得对象的引⽤时,对象的属性是可以延后设置的,但是构造器必须是在获取引⽤之前
    • Spring通过setXxx或者@Autowired⽅法解决循环依赖其实是通过提前暴露⼀个ObjectFactory对象来完成的,简单来说ClassA在调⽤构造器完成对象初始化之后,在调⽤ClassA的setClassB⽅法之前就把ClassA实例化的对象通过ObjectFactory提前暴露到Spring容器中。
    • Spring容器初始化ClassA通过构造器初始化对象后提前暴露到Spring容器。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

Sping IOC 源码剖析_第18张图片

  • 首先对lagouBean进行实例化,将一个lambd表达式的lagouBeanFactory工厂放入三级缓存.然后设置属性,依赖itBean
  • 实例化itBean,将一个lambd表达式的itBeanFactory工厂放入三级缓存,itBean又依赖lagouBean,从三级缓存当中利用lagouBeanFactory产生lagouBean代理对象,设置进itBean中,将lagouBean代理对象放入二级缓存当中,移除三级缓存中的lagouBeanFactory工厂对象。itBean创建完毕,放入一级缓存中,移除三级缓存中的itBeanFactory
  • 将itBean设置到lagouBean中,用二级缓存的lagouBean代理对象覆盖lagouBean,再将lagouBean放入一级缓存中。
  • 产生代理对象的时机
    • 无循环依赖
      Sping IOC 源码剖析_第19张图片

    • 有循环依赖
      Sping IOC 源码剖析_第20张图片

6.注意事项

阅读源码一定要抓主线,不能掉进某一行代码当中陷进去。以具体实例断点调试步步分析。
文章内容输出来源:拉勾教育Java高薪训练营

你可能感兴趣的:(Spring,java,spring)