谈谈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、流程

  1. 创建Bean工厂
  2. 加载配置文件、封装成BeanDefinition对象
  3. 调用BeanFactoryPostProcessor后置处理器
  4. 实例化Bean对象
  5. 调用BeanPostProcessor的postProcessorBeforeInitialization方法
  6. 调用init-method初始化方法
  7. 调用BeanPostProcessor的postProcessorAfterInitialization方法
  8. 生成完整Bean对象
  9. 销毁

五、总结

  1. Spring创建bean主要分为两个步骤,创建原始bean对象,接着去填充对象属性和初始化
  2. 每次创建bean之前,我们都会从缓存中查下有没有该bea.因为是单例,只能有一个
  3. 当我们创建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,走剩下的流程。

posted @ 2022-05-10 13:03  没有你哪有我  阅读(31)  评论(0编辑  收藏  举报