谈谈Spring IOC
准备工作
1、创建A和B类
A类
1 package com.lzp.springbootdemo.bean; 2 3 /** 4 * @Author 14715 5 * @Date 2022/5/9 18:31 6 * @Version 1.0 7 */ 8 public class A { 9 10 private B b; 11 12 public B getB() { 13 return b; 14 } 15 16 public void setB(B b) { 17 this.b = b; 18 } 19 20 public A() { 21 System.out.println("bean A created by spring"); 22 } 23 }
B类
1 package com.lzp.springbootdemo.bean; 2 3 /** 4 * @Author 14715 5 * @Date 2022/5/9 18:31 6 * @Version 1.0 7 */ 8 public class B { 9 10 private A a; 11 12 public A getA() { 13 return a; 14 } 15 16 public void setA(A a) { 17 this.a = a; 18 } 19 20 public B() { 21 System.out.println("bean B created by spring"); 22 } 23 }
2、配置application.xml文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://www.springframework.org/schema/beans" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 6 http://www.springframework.org/schema/context 7 http://www.springframework.org/schema/context/spring-context-4.2.xsd"> 8 9 <bean id="a" class="com.lzp.springbootdemo.bean.A"> 10 <property name="b" ref="b"/> 11 </bean> 12 13 <bean id="b" class="com.lzp.springbootdemo.bean.B"> 14 <property name="a" ref="a"/> 15 </bean> 16 17 </beans>
3、创建测试类
1 package com.lzp.springbootdemo; 2 3 import com.lzp.springbootdemo.bean.A; 4 import com.lzp.springbootdemo.bean.B; 5 import org.springframework.boot.autoconfigure.SpringBootApplication; 6 import org.springframework.context.ApplicationContext; 7 import org.springframework.context.support.ClassPathXmlApplicationContext; 8 9 @SpringBootApplication 10 public class SpringbootDemoApplication { 11 12 public static void main(String[] args) { 13 ApplicationContext beanFactory = new ClassPathXmlApplicationContext("application.xml"); 14 A a = beanFactory.getBean("a", A.class); 15 B b = beanFactory.getBean("b", B.class); 16 } 17 18 }
一、Spring存储Bean的3个Map
1、singletonObjects(一级缓存)
2、earlySingletonObjects(二级缓存)
3、singletonFactories(三级缓存)
二、Spring创建Bean的四个方法
1、getSingleton
2、doCreateBean
3、populateBean
3、addSingleton
三、Debug时要主要的关键性方法
1、refresh(刷新)
2、finishBeanFactoryInitialization(完成BeanFactory的初始化)
3、preInstantiateSingletons
4、getBean
5、doGetBean
6、getSingleton(获取单例Bean)
7、createBean(包含在lambda表达式内)
8、doCreateBean
9、createBeanInstance(创建Bean对象)
10、addSingletonFactory(添加到三级缓存)
11、getEarlyBeanReference(获取早期的Bean引用)
方法上注释的中文翻译:
12、populateBean(填充Bean对象)
13、applyPropertyValues(设置属性值)
14、resolveValueIfNecessary(解析必要的值)
15、resolveReference(解析引用)
16、setPropertyValues(设置属性值)
四、IOC的原理和具体底层实现流程
1、IOC(控制反转)
是理论思想——原来对象的创建是直接由使用者(也就是程序员们)自己手动创建的,而自从Spring出现以后,所有对象的创建、使用以及销毁等生命周期都由Spring进行管理,大大减轻了程序员的负担。而DI(依赖注入)是把对应的属性值注入到对象中,@Autowired、populateBean等都可以完成属性的注入
2、容器
spring通过三个Map集合来存储所有bean对象,且三个Map集合对应三级缓存。bean对象又分为成品和半成品,一级缓存用于存储成品,二级缓存用于存储半成品,三级缓存用于解决AOP产生的代理对象问题
3、流程
- 创建Bean工厂
- 加载配置文件、封装成BeanDefinition对象
- 调用BeanFactoryPostProcessor后置处理器
- 实例化Bean对象
- 调用BeanPostProcessor的postProcessorBeforeInitialization方法
- 调用init-method初始化方法
- 调用BeanPostProcessor的postProcessorAfterInitialization方法
- 生成完整Bean对象
- 销毁
五、总结
- Spring创建bean主要分为两个步骤,创建原始bean对象,接着去填充对象属性和初始化
- 每次创建bean之前,我们都会从缓存中查下有没有该bea.因为是单例,只能有一个
- 当我们创建beanA的原始对象后,并把它放到三级缓存中,接下来就该填充对象属性了,这时候发现依赖了beanB,接着就又去创建beanB,同样的流程,创建完beanB填充属性时又发现它依赖了beanA又是同样的流程
不同的是:
这时候可以在三级缓存中查到刚放进去的原始对象beanA,所以不需要继续创建,用它注入beanB,完成beanB的创建
4、既然beanB创建好了,所以beanA就可以完成填充属性的步骤了,接着执行剩下的逻辑,闭环完成
补充说明
1、Spring解决循环依赖依靠的是Bean的“中间态”这个概念,而这个中间态指的是已经实例化但还没初始化的状态(即半成品)。实例化的过程又是通过构造器创建的,如果A还没创建好出来怎么可能提前曝光,所以构造器的循环依赖无法解决。
2、Spring为了解决单例的循环依赖问题,使用了三级缓存。其中
- 一级缓存为单例池( singletonObjects )
- 二级缓存为提前曝光对象( earlySingletonObjects)
- 三级缓存为提前曝光对象工厂( singletonFactories)
3、假设A、B循环引用,实例化A的时候就将其放入三级缓存中,接着填充属性的时候,发现依赖了B,同样的流程也是实例化后放入三级缓存,接着去填充属性时又发现自己依赖A,这时候从缓存中查找到早期暴露的A,没有AOP代理的话,直接将A的原始对象注入B,完成B的初始化后,进行属性填充和初始化,这时候B完成后,就去完成剩下的A的步骤,如果有AOP代理,就进行AOP处理获取代理后的对象A,注入B,走剩下的流程。