Bean的初始化阶段的步骤比较复杂,所以着重研究Bean的初始化阶段
Spring Bean的初始化过程涉及如下几个过程:
Bean实例化的属性填充
Aware接口属性注入
BeanPostProcess的before()方法回调
InitializingBean接口的初始化方法回调
自定义初始化方法回调
BeanPostProcessor的after()方法回调
Spring在进行属性注入时,会分为以下几种情况:
注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;
注入单向对象引用属性时,从容器中getBean获取后通过set方法反射进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;
注入双向对象引用属性时,就比较复杂了,涉及了循环依赖;
循环依赖
含义:指两个或多个Bean之间有相互依赖关系,并且形成闭环。
循环依赖会导致Bean无法被实例化,程序运行时会出现异常;
解决方案:Spring提供了三级缓存存储完整的Bean实例和半成品Bean实例,
三级缓存:
一级缓存:SingletonBeanRegistry,最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean;
二级缓存:EarlySingletonObjects,早期Bean单例池,缓存半成品的对象,且当前对象已经引用了;
三级缓存:单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean。
举例:
处理流程如下:
1.UserService实例化对象,但尚未初始化,将UserService存储到三级缓存;
2.开始UserService属性注入,发现UserDao需要,从缓存中获取,发现没有UserDao;
3.Spring开始对UserDao实例化对象,但尚未初始化,存放在三级缓存;
4.UserDao属性注入,需要UserService,从三级缓存中找UserService,并获取UserService,将UserService从三级缓存 移入二级缓存;
5.UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二级缓存;
6.UserService注入UserDao;
7.UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存。
具体项目:
两个实体类
package com.ly.pojo;
public class Student {
public Student() {
System.out.println("执行Student无参");
}
}
package com.ly.pojo;
public class Teacher {
private String msg;
private Student student;
public void setMsg(String msg) {
this.msg = msg;
System.out.println("执行Teacher属性赋值");
}
public void setStudent(Student student) {
this.student = student;
System.out.println("执行Teacher属性赋值");
}
public Teacher() {
System.out.println("执行Teacher无参");
}
}
测试一:
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="teacher" class="com.ly.pojo.Teacher">
<property name="msg" value="bbb"></property>
<property name="student" ref="student"></property>
</bean>
<bean class="com.ly.pojo.Student" id="student"></bean>
</beans>
package com.ly.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test1 {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationConText.xml");
Object teacher = applicationContext.getBean("teacher");
System.out.println(teacher);
}
}
测试结果
测试二:
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.ly.pojo.Student"></bean>
<bean id="teacher" class="com.ly.pojo.Teacher">
<property name="msg" value="aaa"></property>
<property name="student" ref="student"></property>
</bean>
</beans>
package com.ly.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test1 {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationConText.xml");
Object student = applicationContext.getBean("student");
System.out.println(student);
}
}