spring源码阅读之bean生命周期
本文内容纲要:
- Spring Bean的生命周期- 1. bean元信息定义阶段
- API方式
- XML方式
- ANNOTATION注解方式
- properties的方式
- 2. BEAN元信息解析阶段
- 解析XML文件
- 解析注解
- properties文件解析
- 3. bean注册阶段
- 4. beanDefinition合并阶段
- 5. bean类加载阶段
- 6. bean实例化阶段
- 6.1 实例化前阶段
- 6.2 实例化阶段
- 7. beanDefinition合并后处理
- 8. bean属性赋值阶段
- 8.1 bean初始化后阶段
- 8.2 bean属性赋值前阶段
- 8.3 bean属性赋值阶段
- 9. bean初始化阶段
- 9.1 bean Aware接口回调阶段
- 9.2 bean初始化前阶段
- 9.3 bean初始化阶段
- 9.4 bean初始化后阶段
- 9.5 bean初始化完成阶段
- 10. 所有单例bean初始化完成阶段
- 11. bean使用阶段
- 12. bean销毁阶段
Spring Bean的生命周期
1. bean元信息定义阶段
spring要创建bean首先需要定义bean的配置信息,这些信息我们称为bean的元信息。
什么是元信息?
元信息: 用来描述数据的数据
bean元信息定义有四种方式:
- API方式
- XML方式
- 注解方式
- properties方式
创建一个实体类UserInfo对象:
@Data@Accessors(chain = true)
public class UserInfo {
private String name;
private Integer age;
private String[] hobby;
}
下面来看一下这四种方式:
API方式
首先来看一下Api方式定义元数据,其他三种方式最终都会采用这种方式来定义Bean信息。
public class ApplicationDemo { @Test
public void fun1() {
// API的方式定义bean元数据
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(UserInfo.class)
.addPropertyValue("name", "张三").addPropertyValue("age", 18)
.addPropertyValue("hobby", new String[]{"唱歌", "运动"}).getBeanDefinition();
System.out.println(beanDefinition);
}
}
运行结果:
Generic bean: class [com.xiazhi.spring.bean.UserInfo]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
XML方式
使用xml配置文件的方式定义bean信息
<?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 class="com.xiazhi.spring.bean.UserInfo">
<property name="name" value="zhangsan"/>
<property name="age" value="18"/>
<property name="hobby">
<array>
<value>唱歌</value>
<value>睡觉</value>
</array>
</property>
</bean>
</beans>
ANNOTATION注解方式
@Data@Accessors(chain = true)
@Component
@Scope
@Lazy
public class UserInfo {
private String name;
private Integer age;
private String[] hobby;
}
或者通过bean注解的方式定义bean
@Configurationpublic class UserConfig {
@Bean
@Primary
@Lazy
@Scope
public UserInfo userInfo() {
return new UserInfo().setName("zhangsan").setAge(18).setHobby(new String[]{"吃饭", "java"});
}
}
properties的方式
这种方式用这不方便,所以比较少见。、在classpath下定义userInfo.properties文件:
userInfo.(class)=com.xiazhi.spring.bean.UserInfouserInfo.name=张一
userInfo.age=20
userInfo.hobby=吃饭,睡觉
userInfo.(scope)=prototype
userInfo.(primary)=true
userInfo.(lazy-init)=true
2. BEAN元信息解析阶段
通过上面的方式定义的所有bean信息都会被spring解析成BeanDefinition类型,因此上面说其他三种方式都会解析成API的方式。
因为API的方式是直接定义了BeanDefinition类型。
解析XML文件
@Test public void xml() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("classpath:application.xml");
String[] names = beanFactory.getBeanDefinitionNames();
for (String name : names) {
System.out.println(beanFactory.getBeanDefinition(name));
}
}
解析注解
@Test public void annotation() {
DefaultListableBeanFactory registry = new DefaultListableBeanFactory();
AnnotatedBeanDefinitionReader beanDefinitionReader = new AnnotatedBeanDefinitionReader(registry);
beanDefinitionReader.registerBean(UserInfo.class);
for (String name : registry.getBeanDefinitionNames()) {
System.out.println(registry.getBeanDefinition(name));
}
}
properties文件解析
@Test public void properties() {
DefaultListableBeanFactory registry = new DefaultListableBeanFactory();
PropertiesBeanDefinitionReader definitionReader = new PropertiesBeanDefinitionReader(registry);
definitionReader.loadBeanDefinitions("classpath:userInfo.properties");
for (String name : registry.getBeanDefinitionNames()) {
System.out.println(registry.getBeanDefinition(name));
}
}
3. bean注册阶段
我们定义的bean元信息配置文件等,经过beanDefinitionReader的解析后,会注册进bean工厂中,我们才可以在bean工厂中获取到Bean定义信息。
具体代码在:registerBeanDefinitions
方法内完成
4. beanDefinition合并阶段
在上一个阶段中注册的beanDefinition是不完整的bean。例如:
定义一个类ServiceB:
@Datapublic class ServiceB{
private String desc;
private String name;
private String age;
}
<bean id="abstract" abstract="true">
<property name="name" value="lisi"/>
<property name="age" value="20"/>
</bean>
<bean id="serviceB" class="com.xiazhi.spring.bean.ServiceB" parent="abstract">
<property name="desc" value="spring学习"/>
</bean>
@Test
public void fun1() {
DefaultListableBeanFactory registry = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.loadBeanDefinitions("classpath:application.xml");
for (String name : registry.getBeanDefinitionNames()) {
System.out.println("beanDefinition合并前:");
System.out.println(name + "-->" + registry.getBeanDefinition(name).getPropertyValues());
System.out.println("beanDefinition合并后:");
System.out.println(name + "" + registry.getMergedBeanDefinition(name).getPropertyValues());
}
}
运行结果:
beanDefinition合并前:serviceB-->PropertyValues: length=1; bean property 'desc'
beanDefinition合并后:
serviceBPropertyValues: length=3; bean property 'name'; bean property 'age'; bean property 'desc'
看一下上面代码,serviceB的父级是abstract,xml文件被解析后生成GenericBeanDefinition
,这个beanDefinition信息是不整的,只有当前定义的标签
的内容,不包含从父级中继承过来的属性信息,因此需要使用 getMergedBeanDefinition()
方法来将GenericBeanDefinition类
转为RootBeanDefinition
类型
5. bean类加载阶段
在AbstractBeanDefinition
类中有一个字段:
private volatile Object beanClass;
这个字段有两种取值:
- Bean的Class对象
- Bean的全路径名
当值为Bean的全路径名时,需要将它转成Bean的class对象。在BeanDefinition
合并阶段获取到的RootBeanDefinition
,对beanClass进行解析,将类型
转换为Class对象,然后赋值给beanClass对象
6. bean实例化阶段
在上一步获得了Bean的Class对象,就可以根据反射来实例化对象了,对象的实例化前会调用
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
类下的方法:
在这个类中有属性:private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
这个类有一个唯一实现DefaultListableBeanFactory
@Nullable protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
从方法内容可以看出,会循环所有的BeanPostProcessors,然后判断类型是否是InstantiationAwareBeanPostProcessor
类型如果是的话就调用接口的一个方法。
看一下这个接口:
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { // 实例化前调用
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
// 实例化后调用
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
// 属性赋值后调用
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
6.1 实例化前阶段
在bean实例化前会调用上面接口中的postProcessBeforeBeanInstantiation
方法,因此我们写一个这个类的实现类实现这个接口的内容
public class BeanBeforeInstance implements InstantiationAwareBeanPostProcessor { public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("实例化:" + beanName + "前调用");
return null;
}
}
@Component
public class ServiceA {
public ServiceA() {
System.out.println("调用A的构造方法创建A");
}
}
@Import(BeanBeforeInstance.class)
public class BeanScanConfig {
}
测试上面的过程:
@Test public void fun2() {
new AnnotationConfigApplicationContext(BeanScanConfig.class);
}
运行结果:
实例化:beanScanConfig前调用实例化:serviceA前调用
调用A的构造方法创建A
实例化:userConfig前调用
6.2 实例化阶段
bean实例化阶段,spring容器通过调用构造器创建bean对象实例,这一个阶段spring也给我们提供了接口,用来决定用那儿一个构造器实例对象。
spring提供了InstantiationAwareBeanPostProcessor接口的一个子接口:SmartInstantiationAwareBeanPostProcessor
来实现。
这个接口提供了一个方法:
@Nullable default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
throws BeansException {
return null;
}
由方法名可以看出--确定候选构造函数,这个方法的作用就是确定要使用哪儿个构造方法来创建Bean。
下面验证这个方法:
创建一个注解:
@Target(ElementType.CONSTRUCTOR)@Retention(RetentionPolicy.RUNTIME)
public @interface Candidate {
}
可以看出这个注解使用在构造器上的
@Componentpublic class ServiceB{
private String desc;
private String name;
private String age;
public ServiceB() {
}
@Candidate
public ServiceB(@Autowired(required = false) String name) {
System.out.println("调用一个参数的构造方法");
this.name = name;
}
public ServiceB(String name, String age) {
this.name = name;
this.age = age;
}
}
这个类有多个构造器,spring会返回被Candidate标注的构造器
实现SmartInstantiationAwareBeanPostProcessor接口:
public class ServiceBeanInstancePostProcessor implements SmartInstantiationAwareBeanPostProcessor { @Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("bean实例化前调用");
return null;
}
@Override
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
System.out.println(String.format("有%d个构造方法", declaredConstructors.length));
Constructor[] constructors = Arrays.stream(declaredConstructors).filter(f -> f.isAnnotationPresent(Candidate.class)).toArray(Constructor[]::new);
System.out.println("构造器:" + constructors.length);
return constructors.length == 0 ? null : constructors;
}
}
运行结果:
有3个构造方法构造器:1
调用一个参数的构造方法
7. beanDefinition合并后处理
会调用MergedBeanDefinitionPostProcessor
的postProcessMergedBeanDefinition方法
此方法参数BeanDefinition是合并后的RootBeanDefinition, 此时在bean实例化完成,bean属性赋值阶段开始前,可以在此修改bean的信息
public class ServiceMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor { @Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
System.out.println(beanDefinition.getPropertyValues());
beanDefinition.getPropertyValues().add("desc", "调用merged接口");
}
}
<bean id="abstract" abstract="true">
<property name="name" value="lisi"/>
<property name="age" value="20"/>
</bean>
<bean id="serviceB" class="com.xiazhi.spring.bean.ServiceB" parent="abstract">
<property name="desc" value="spring学习"/>
</bean>
<bean class="com.xiazhi.spring.bean.ServiceMergedBeanDefinitionPostProcessor"/>
运行:
@Test public void fun3() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
ServiceB serviceB = context.getBean(ServiceB.class);
System.out.println(serviceB);
}
结果:
调用无参构造PropertyValues: length=3; bean property 'name'; bean property 'age'; bean property 'desc'
ServiceB(desc=调用merged接口, name=lisi, age=20)
8. bean属性赋值阶段
8.1 bean初始化后阶段
在这个阶段会调用 InstantiationAwareBeanPostProcessor
的postProcessAfterBeanInstantiation
方法
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return true;
}
8.2 bean属性赋值前阶段
在这个阶段会调用 postProcessProperties
方法:
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
return null;
}
这个方法有两个非常重要的实现类:AutowiredAnnotationBeanPostProcessor
和 CommonAnnotationBeanPostProcessor
- AutowiredAnnotationBeanPostProcessor: @Autowired注解和@Value注解赋值
- CommonAnnotationBeanPostProcessor: @Resource注解标注的字段和方法赋值
8.3 bean属性赋值阶段
通过调用反射的set方法给字段赋值
案例:
public class BeanPropertyPostProcessor implements InstantiationAwareBeanPostProcessor { /**
* 在实例化后,beanDefinition合并后阶段处理完,会调用此方法
* @param bean 实例化对象
* @param beanName bean名称
* @return 如果此方法返回false,那么bean赋值阶段后两个阶段(bean属性赋值前阶段,bean属性赋值阶段都不会执行)
* @throws BeansException
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (bean.getClass().isAssignableFrom(ServiceB.class)) {
System.out.println("进入ServiceB实例化后阶段,属性赋值前阶段");
return true;
}
return false;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
System.out.println("进入ServiceB属性赋值前阶段");
System.out.println("要赋值的属性有:" + pvs + "可以在此对值进行修改");
if (pvs instanceof MutablePropertyValues) {
MutablePropertyValues mpvs = (MutablePropertyValues) pvs;
mpvs.add("name", "改后的name");
}
return pvs;
}
}
<bean id="abstract" abstract="true">
<property name="name" value="lisi"/>
<property name="age" value="20"/>
</bean>
<bean id="serviceB" class="com.xiazhi.spring.bean.ServiceB" parent="abstract">
<property name="desc" value="spring学习"/>
</bean>
<bean class="com.xiazhi.spring.bean.ServiceMergedBeanDefinitionPostProcessor"/>
<bean class="com.xiazhi.spring.bean.BeanPropertyPostProcessor"/>
@Test
public void fun3() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
ServiceB serviceB = context.getBean(ServiceB.class);
System.out.println(serviceB);
}
运行结果:
调用无参构造PropertyValues: length=3; bean property 'name'; bean property 'age'; bean property 'desc'
进入ServiceB实例化后阶段,属性赋值前阶段
进入ServiceB属性赋值前阶段
要赋值的属性有:PropertyValues: length=3; bean property 'name'; bean property 'age'; bean property 'desc'可以在此对值进行修改
开始进行bean属性赋值
ServiceB(desc=调用merged接口, name=改后的name, age=20)
9. bean初始化阶段
9.1 bean Aware接口回调阶段
bean Aware接口回调主要包括如下几个接口:
public class BeanAware implements BeanFactoryAware, BeanClassLoaderAware, BeanNameAware { private ClassLoader classLoader;
private BeanFactory beanFactory;
private String name;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("classLoaderAware接口回调");
this.classLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware接口回调");
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String name) {
System.out.println("BeanNameAware 接口回调");
this.name = name;
}
}
运行:
@Test public void fun4() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanAware.class);
}
结果:
BeanNameAware 接口回调classLoaderAware接口回调
BeanFactoryAware接口回调
9.2 bean初始化前阶段
在bean初始化之前会调用BeanPostProcessor接口的postProcessorBeforeBeanInitialization方法
@Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
这个接口有两个比较重要的实现类:
ApplicationContextAwareProcessor
:回调六个Aware接口
CommonAnnotationBeanPostProcessor
:调用
@postConstruct
注解标注的方法
9.3 bean初始化阶段
- 调用
@PostConstruct
注解标注的方法 - 调用
InitializingBean
接口的afterPropertiesSet
方法 - 调用
<bean init-method=""/>
指定的方法
9.4 bean初始化后阶段
调用BeanPostProcessor接口的postProcessAfterBeanInitialization()方法
9.5 bean初始化完成阶段
10. 所有单例bean初始化完成阶段
在所有的单例bean注册完成后,会调用SmartInitializingSingleton接口的afterSingletonInstantiated()方法
public class ServiceSmartInitializingSingletonBean implements SmartInitializingSingleton { @Override
public void afterSingletonsInstantiated() {
System.out.println("阶段10:所有单例bean实例化完调用");
}
}
11. bean使用阶段
12. bean销毁阶段
bean销毁阶段调用顺序:
- @preDestroy注解标记销毁方法
Bean销毁阶段会调用
DestructionAwareBeanPostProcessor
接口的 postProcessBeforeDestruction()方法这个方法有一个重要的实现类:
CommonAnnotationBeanPostProcessor
在这个类中会调用 @preDestroy注解标注的方法 - DisposableBean接口方法
- 自定义销毁方法
本文内容总结:Spring Bean的生命周期,1. bean元信息定义阶段,API方式,XML方式,ANNOTATION注解方式,properties的方式,2. BEAN元信息解析阶段,解析XML文件,解析注解,properties文件解析,3. bean注册阶段,4. beanDefinition合并阶段,5. bean类加载阶段,6. bean实例化阶段,6.1 实例化前阶段,6.2 实例化阶段,7. beanDefinition合并后处理,8. bean属性赋值阶段,8.1 bean初始化后阶段,8.2 bean属性赋值前阶段,8.3 bean属性赋值阶段,9. bean初始化阶段,9.1 bean Aware接口回调阶段,9.2 bean初始化前阶段,9.3 bean初始化阶段,9.4 bean初始化后阶段,9.5 bean初始化完成阶段,10. 所有单例bean初始化完成阶段,11. bean使用阶段,12. bean销毁阶段,
原文链接:https://www.cnblogs.com/Zs-book1/p/14371136.html
以上是 spring源码阅读之bean生命周期 的全部内容, 来源链接: utcz.com/z/362497.html