参考: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加载顺序的控制