一、Spring中Bean的生命周期
当我们启动Spring项目的时候,就会初始化Spring的容器,Spring就会扫描启动引导类所在包及其子包中类的注解,并调用这些加了注解的类的构造方法创建对象(控制翻转),再创建了这些类的对象之后,就会找使用了@Autowired注解的地方进行赋值(依赖注入)。随后就会将创建的对象初始化(init)。最后Spring容器销毁的时候,创建的对象也会销毁(destroy)。
总结:
1、调用这些加了注解的类的构造方法创建对象(控制翻转)
2、找使用了@Autowired注解的地方进行赋值(依赖注入)
3、将创建的对象初始化(init)
4、将创建的对象销毁。
1.1、代码演示
1、定义class A,并再A上使用@Component注解
2、断点打在SpringApplication.run方法上
3、启动应用程序,不初始化容器
当断点停留在SpringApplication.run方法时,也就是还没有初始化容器时,此时Spring并没有创建相关对象(因为此时Spirng的容器还没有初始化)。
4、初始化Spirng容器
将断点放行,可以在控制台发现实例A的生命周期和"一"中的总结是一样的。
二、循环依赖问题
2.1、set方式循环依赖
定义class A,和1.1中的一模一样,在class A中的set方法中依赖注入B
定义class B,在class B中的set方法中依赖注入A。
此时就会出现循环依赖的问题:
因为我们从"一"中得知Bean的生命周期的流程大概是:
1、创建对象
2、依赖注入,其中就包括set方法依赖注入。
3、初始化
假如Spring首先创建了对象A,然后调用A类中的set方法对方法参数b进行依赖注入赋值, 此时就要在容器中去找对象B,而此时可能对象B还没有创建成功,所以就出现了循环依赖的问题。
2.2、 set方式循环依赖的解决办法
在springboot2.6.0之前自动解决,无需任何配置。
在springboot2.6.0之后的版本中需要在配置文件中开启运行set方式循环依赖
spring.main.allow-circular-references=true
2.3、构造方式循环依赖
构造方式循环依赖的原因和2.1中set方式循环依赖的原因差不多,不在过多介绍,下面进行代码的演示。
C中的构造方法依赖注入D
D中的构造方法依赖注入C
如果构造方法中只有一个方法参数,可以省略 @Autowired,所以上面的C、D中的构造方法里面并没有使用@Autowired,注解。
2.3.4、构造方式循环依赖的解决办法
在其中一个类的构造方法中,加上@Lazy注解即可。
在C的构造方法中使用@Lazy注解,表示创建D的代理对象而不是真实对象进行注入。