Java Spring 生命周期
1. 概述
Spring Bean的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:
- Bean的实例化阶段: Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是sinaleton的是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化;
- Bean的初始化阶段: Bean创建之后还仅仅是个"半成品”,还需要对Bean实例的属性进行填充、执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,后面要学习的Spring的注解功能等spring高频面试题Bean的循环引用问题都是在这个阶段体现的:
- Bean的完成阶段: 经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期
2. 初始化阶段
2.1 Bean的初始化阶段涉及过程
Spring Bean的初始化过程涉及如下几个过程
- Bean实例的属性填充
- Aware接口属性注入
- BeanPostProcessor的before()方法回调InitializingBean接口的初始化方法回调
- 自定义初始化方法init回调
- BeanPostProcessor的after()方法回调
2.2 Bean实例属性填充
Spring在进行属性注入时,会分为如下几种情况:
- 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;
- 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;
- 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题
2.2.1 propertyValues
BeanDefinition 中有对当前Bean实体的注入信息通过属性propertyValues进行了存储
PersonDao.java
package org.example;
public interface PersonDao {
}
UserDao.java
package org.example;
public interface UserDao {
}
UserDaoImpl.java
package org.example;
public class UserDaoImpl implements UserDao {
}
PersonDaoImpl.java
package org.example;
public class PersonDaoImpl implements PersonDao{
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
private String name;
private UserDao userDao;
}
beans.xml
<bean class="org.example.UserDaoImpl" id="userDao"/>
<bean class="org.example.PersonDaoImpl" id="personDao">
<property name="userDao" ref="userDao"/>
<property name="name" value="名字"/>
</bean>
主函数调用
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
例如PersonDao的属性信息如下:
2.2.2 循环引用
多个实体之间相互依赖并形成闭环的情况就叫做”循环依赖”,也叫做”循环引用。
死循环原理图
UserDaoImpl.java
package org.example;
public class UserDaoImpl implements UserDao {
private UserService userService;
public UserService getUserService() {
return userService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}
UserServiceImpl.java
package org.example;
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
beans.xml
<bean class="org.example.UserDaoImpl" id="userDao">
<property name="userService" ref="userService"/>
</bean>
<bean class="org.example.UserServiceImpl" id="userService">
<property name="userDao" ref="userDao"/>
</bean>
2.2.3 三级缓存解决循环引用问题
- Spring提供了三级缓存存储完整Bean实例和半成品Bean实例,用于解决循环引用问题
- 在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:
UserService和UserDao循环依赖的过程结合上述三级缓存描述一下
- UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存
- UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;
- UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存;
- UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移入二级缓存:UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存
- UserService 注入UserDao:
- UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存
2.3 常用的Aware接口
Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封装性,我们接触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用不到这些对象,如果用到了就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象。
在pom.xml添加ServletContext依赖jar包
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
UserServiceImpl.java
package org.example;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class UserServiceImpl implements UserService, ApplicationContextAware, BeanNameAware, BeanFactoryAware {
public UserServiceImpl() {
System.out.println("构造方法执行");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactory--------" + beanFactory.toString());
}
@Override
public void setBeanName(String s) {
System.out.println("BeanName--------" + s);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("ApplicationContext--------" + applicationContext.toString());
}
}
主函数调用
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
System.out.println(userService);
}
执行结果
构造方法执行
BeanName--------userService
BeanFactory--------org.springframework.beans.factory.support.DefaultListableBeanFactory@319b92f3: defining beans [userDao,userService]; root of factory hierarchy
ApplicationContext--------org.springframework.context.support.ClassPathXmlApplicationContext@1a93a7ca, started on Sat Mar 04 15:19:28 CST 2023
org.example.UserServiceImpl@436a4e4b
评论 (0)