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. 自定义销毁方法
  • 相关阅读:
    HDU 1010 Tempter of the Bone(DFS剪枝)
    HDU 1013 Digital Roots(九余数定理)
    HDU 2680 Choose the best route(反向建图最短路)
    HDU 1596 find the safest road(最短路)
    HDU 2072 单词数
    HDU 3790 最短路径问题 (dijkstra)
    HDU 1018 Big Number
    HDU 1042 N!
    NYOJ 117 求逆序数 (树状数组)
    20.QT文本文件读写
  • 原文地址:https://www.cnblogs.com/Zs-book1/p/14371136.html
Copyright © 2011-2022 走看看