spring源码阅读之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. 自定义销毁方法
原文地址:https://www.cnblogs.com/Zs-book1/p/14371136.html