Spring IOC和DI、bean的生命周期和作用域、循环依赖(三个缓存)、控制Bean的加载顺序

参考:https://yexindong.blog.csdn.net/article/details/117173285
https://www.zhihu.com/question/362583020
https://blog.csdn.net/yessimida/article/details/123311432

一:Spring IOC和DI

1.IOC:Inversion of Control 控制反转

控制:对象的创建和销毁由用户控制变为了由容器控制
在这里插入图片描述

反转:正转其实就是对象去找实例,而反转就是实例来找对象
在这里插入图片描述

2.DI:Dependency Inject 依赖注入

依赖:对象依赖容器
注入:容器将对象注入

二:bean的生命周期和作用域

1.bean的生命周期:

1.类加载:编译之后加载到JVM
2.生成封装Bean信息的BeanDefinition对象,然后把Bean信息放到BeanDefinitionMap
3.实例化:创建一个实例
4.初始化:给对象初始化
5.前置处理:Spring框架的一些逻辑
6.后置处理:Spring框架的一些逻辑
7.销毁:调销毁方法

在这里插入图片描述

2.bean的模式(作用域):

singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的(单例模式)
prototype : 每次请求都会创建一个新的bean 实例(原型模式)
request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request内有效。
session : 每一个 HTTP Session 会产生一个新的 bean,该 bean 仅在当前 HTTP session
内有效。

三:循环依赖:两个Bean互相一个属性,是对方这个类对象

1.循环依赖:

@Service
public class A {
    @Autowired
    private B b;
}

@Service
public class B {
    @Autowired
    private A a;
}

在这里插入图片描述

2.Bean的创建分三步:

实例化:createBeanInstance,就是 new 了个对象
属性注入: set 一些属性值
初始化:initializeBean,执行一些 aware 接口中的方法,initMethod,AOP代理等

3.循环依赖解决: 三个缓存(Map)

解决:
先创建 A,此时的 A 是不完整的(没有注入 B),用个二级缓存earlySingletonObjects保存这个不完整的 A,再创建 B ,B 需要 A,所以从二级缓存得到“不完整”的 A,此时的 B 就完整了,把B放入到一级缓存singletonObjects,然后 A 就可以注入 B,然后 A 就完整了,把A也放入一级缓存。B 也完整了,且它们是相互依赖的

三个缓存:

一级缓存,singletonObjects,存储所有已创建完毕的单例 Bean (完整的 Bean)
二级缓存,earlySingletonObjects,存储所有仅完成实例化,但未属性注入和初始化的 Bean
三级缓存,singletonFactories,存储能建立这个 Bean 的一个工厂,通过工厂能获取这个 Bean,延迟化 Bean 的生成,工厂生成的 Bean 会塞入二级缓存

三个缓存配合的过程:

获取Bean 的时候会通过 BeanName 先去 一级缓存singletonObjects查找完整的 Bean,如果找到则直接返回。
如果找不到则会去二级缓存earlySingletonObjects查找 Bean,如果找到则返回。
如果找不到就去 三级缓存singletonFactories通过 BeanName 查找到对应的工厂,如果存着工厂则通过工厂创建 Bean ,并且放置到 earlySingletonObjects 中

循环依赖需要三级缓存的原因(循环依赖两级就可以解决):

如果 A 需要被代理,那么 B 依赖的 A 是已经被代理的 A,所以我们不能返回 A 给 B,而是返回代理的 A 给 B。
这个工厂的作用就是判断这个对象是否需要代理,如果否则直接返回,如果是则返回代理对象。

在这里插入图片描述

四:控制Bean的加载顺序

方法一:@DependsOn(“Bean B”)注解控制 :顺序是TrainTask -> AircraftTask -> CarTask

@Configuration
public class TrainTask {
    @PostConstruct
    public void init(){
        System.out.println("Train初查询数据存入redis..........");
    }
}

@Configuration
@DependsOn("trainTask")
public class AircraftTask {
    @PostConstruct
    public void init(){
        System.out.println("Aircraft获取Train存入redis的数据..........");
    }
}
 
@Configuration
@DependsOn("aircraftTask")
public class CarTask {
    @PostConstruct
    public void init(){
        System.out.println("CarTask获取到Aircraft的数据..........");
    }
}
 

方法二:实现BeanDefinitionRegistryPostProcessor接口,在postProcessBeanDefinitionRegistry方法中通过BeanDefinitionRegistry获取到所有bean的注册信息,将bean保存到LinkedHashMap中,并从BeanDefinitionRegistry中删除,然后将保存的bean定义排序后,重新再注册到BeanDefinitionRegistry中,即可实现bean加载顺序的控制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值