zoukankan      html  css  js  c++  java
  • 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. 自定义销毁方法
  • 相关阅读:
    uiwebview的基本使用
    当你在浏览器地址栏输入一个URL后回车,将会发生的事情?
    开车误闯红灯的补救方法 (以及由此引发的一些思考)
    Android源码剖析之Framework层基础版(窗口、linux、token、Binder)
    Android项目框架之图片加载框架的选择
    通过runtime替换系统类实现的代码(从github开源库fdstackview中摘录)
    awakeFromNib相关知识详解
    推送服务推荐
    由微博图床挂掉之后想到的
    Mac下如何配置环境变量
  • 原文地址:https://www.cnblogs.com/Zs-book1/p/14371136.html
Copyright © 2011-2022 走看看