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

@Configuration

public 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.UserInfo

userInfo.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:

@Data

public 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 {

}

可以看出这个注解使用在构造器上的

@Component

public 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初始化后阶段

在这个阶段会调用 InstantiationAwareBeanPostProcessorpostProcessAfterBeanInstantiation方法

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;

}

这个方法有两个非常重要的实现类:AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor

  • 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初始化阶段

  1. 调用@PostConstruct注解标注的方法
  2. 调用InitializingBean接口的afterPropertiesSet方法
  3. 调用<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销毁阶段调用顺序:

  1. @preDestroy注解标记销毁方法

    Bean销毁阶段会调用 DestructionAwareBeanPostProcessor接口的 postProcessBeforeDestruction()方法

    这个方法有一个重要的实现类: CommonAnnotationBeanPostProcessor 在这个类中会调用 @preDestroy注解标注的方法

  2. DisposableBean接口方法
  3. 自定义销毁方法

本文内容总结: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

回到顶部