美文网首页
Java面试题:Spring Bean的生命周期

Java面试题:Spring Bean的生命周期

作者: 程序员驴子酱 | 来源:发表于2021-12-10 17:11 被阅读0次

    1.概述

    Spring作为当前Java最流行、最强大的轻量级框架,我们在面试框架时会经常被问到,很多时候回答的不完整,下面针对该问题,我详细整理出该如何回答以及面试官想要了解的你对知识理解的深度。

    2.生命周期流程图

    Spring Bean的生命周期分为四个阶段:实例化 Instantiation --> 属性赋值 Populate --> 初始化 Initialization --> 销毁 Destruction

    生命周期1.png

    (1)实例化Bean:
    对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean

    (2)设置对象属性(依赖注入):

    实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成属性设置与依赖注入。

    (3)处理Aware接口:

    Spring会检测该对象是否实现了xxxAware接口,通过Aware类型的接口,可以让我们拿到Spring容器的一些资源:

    • 如果这个Bean实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,传入Bean的名字;
    • 如果这个Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。
    • 如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
    • 如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;

    (4)BeanPostProcessor前置处理:

    如果想对Bean进行一些自定义的前置处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。

    (5)InitializingBean:

    如果Bean实现了InitializingBean接口,执行afeterPropertiesSet()方法。

    (6)init-method:

    如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。

    (7)BeanPostProcessor后置处理:

    如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

    (8)DisposableBean:

    当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;

    (9)destroy-method:

    最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

    3.生命周期接口分类

    Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

    333.png

    (1)Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法

    (2)Bean级生命周期接口方法:这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法

    (3)容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。

    (4)工厂后处理器接口方法:这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器  接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

    4.案例演示

    我们用一个简单的Spring Bean来演示一下Spring Bean的生命周期。

    (1)首先是一个简单的Spring Bean,调用Bean自身的方法和Bean级生命周期接口方法,为了方便演示,它实现了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这4个接口,同时有2个方法,对应配置文件中<bean>的init-method和destroy-method。如下:

    package com.atguigu.pojo;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.*;
    
    /**
     * @ClassNAME Person
     * @Description
     * @Author  atguigu
     * @Date 2021/10/25 14:54
     * @Version 1.0
     **/
    public class Person implements BeanFactoryAware, BeanNameAware,
            InitializingBean, DisposableBean {
        private String name;
        private String address;
        private int age;
    
        private BeanFactory beanFactory;
        private String beanName;
    
        public Person() {
            System.out.println("【构造器】调用Person的构造器实例化");
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", address='" + address + '\'' +
                    ", age=" + age +
                    ", beanFactory=" + beanFactory +
                    ", beanName='" + beanName + '\'' +
                    '}';
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            System.out.println("【注入属性】注入属性name");
            this.name = name;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            System.out.println("【注入属性】注入属性address");
            this.address = address;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            System.out.println("【注入属性】注入属性age");
            this.age = age;
        }
    
        // 这是BeanFactoryAware接口方法
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            System.out
                    .println("【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()");
            this.beanFactory = beanFactory;
        }
    
        // 这是BeanNameAware接口方法
        @Override
        public void setBeanName(String s) {
            System.out.println("【BeanNameAware接口】调用BeanNameAware.setBeanName()");
            this.beanName = s;
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("【DiposibleBean接口】调用DiposibleBean.destory()");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out
                    .println("【InitializingBean接口】调用InitializingBean.afterPropertiesSet()");
        }
    
        // 通过<bean>的init-method属性指定的初始化方法
        public void myInit() {
            System.out.println("【init-method】调用<bean>的init-method属性指定的初始化方法");
        }
    
        // 通过<bean>的destroy-method属性指定的初始化方法
        public void myDestory() {
            System.out.println("【destroy-method】调用<bean>的destroy-method属性指定的初始化方法");
        }
    }
    

    (2)接下来是演示BeanPostProcessor接口的方法,如下

    package com.atguigu.springtest;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    /**
     * @ClassNAME MyBeanPostProcessor
     * @Description
     * @Author  atguigu
     * @Date 2021/10/25 15:12
     * @Version 1.0
     **/
    public class MyBeanPostProcessor implements BeanPostProcessor {
        public MyBeanPostProcessor(){
            super();
            System.out.println("这是BeanPostProcessor实现类构造器!!");
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改!");
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改!");
            return bean;
        }
    }
    
    

    (3)InstantiationAwareBeanPostProcessor 接口本质是BeanPostProcessor的子接口,一般我们继承Spring为其提供的适配器类InstantiationAwareBeanPostProcessorAdapter来使用它,如下:

    package com.atguigu.springtest;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.PropertyValues;
    import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
    
    import java.beans.PropertyDescriptor;
    
    /**
     * @ClassNAME MyInstantiationAwareBeanPostProcessor
     * @Description
     * @Author  atguigu
     * @Date 2021/10/25 15:15
     * @Version 1.0
     **/
    public class MyInstantiationAwareBeanPostProcessor extends
            InstantiationAwareBeanPostProcessorAdapter {
        public  MyInstantiationAwareBeanPostProcessor(){
            System.out
                    .println("这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!");
        }
    
        @Override
        public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
            System.out .println("InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法");
            return pvs;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out .println("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法");
            return bean;
        }
    
        @Override
        public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
            System.out .println("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法");
            return null;
        }
    
    }
    

    这个有3个方法,其中第二个方法postProcessAfterInitialization就是重写了BeanPostProcessor的方法。第三个方法postProcessPropertyValues用来操作属性,返回值也应该是PropertyValues对象。

    (4)演示工厂后处理器接口方法,如下:

    package com.atguigu.springtest;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    
    /**
     * @ClassNAME MyBeanFactoryPostProcessor
     * @Description
     * @Author  atguigu
     * @Date 2021/10/25 15:21
     * @Version 1.0
     **/
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        public MyBeanFactoryPostProcessor() {
            super();
            System.out.println("这是BeanFactoryPostProcessor实现类构造器!!");
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
            System.out
                    .println("BeanFactoryPostProcessor调用postProcessBeanFactory方法");
            BeanDefinition bd = configurableListableBeanFactory.getBeanDefinition("person");
            bd.getPropertyValues().addPropertyValue("phone", "110");
        }
    }
    

    (5)配置文件如下application.xml,很简单,使用ApplicationContext,处理器不用手动注册:

    <?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 id="person" class="com.atguigu.pojo.Person" init-method="myInit" destroy-method="myDestory">
            <property name="name" value="尚硅谷"/>
            <property name="address" value="武汉"/>
            <property name="age" value="22"/>
        </bean>
    
        <bean id="beanPostProcessor" class="com.atguigu.springtest.MyBeanPostProcessor">
        </bean>
    
        <bean id="instantiationAwareBeanPostProcessor" class="com.atguigu.springtest.MyInstantiationAwareBeanPostProcessor">
        </bean>
    
        <bean id="beanFactoryPostProcessor" class="com.atguigu.springtest.MyBeanFactoryPostProcessor">
        </bean>
    </beans>
    

    (6)测试一下:

    package com.atguigu.springtest;
    
    import com.atguigu.pojo.Person;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * @ClassNAME TestPerson
     * @Description
     * @Author  atguigu
     * @Date 2021/10/25 15:02
     * @Version 1.0
     **/
    
    public class BeanLifeCycle {
        public static void main(String[] args) {
            System.out.println("现在开始初始化容器");
            ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
            System.out.println("容器初始化成功");
    
            Person person = (Person)ac.getBean("person");
            System.out.println(person);
    
            System.out.println("现在开始关闭容器!");
            ((ClassPathXmlApplicationContext)ac).registerShutdownHook();
        }
    }
    

    结果如下:

    现在开始初始化容器
    15:30:26,604 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
    15:30:26,604 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
    15:30:26,604 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [file:/E:/ideaworkspace_j2ee/MyBatisTest/target/classes/logback.xml]
    15:30:26,799 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
    15:30:26,805 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
    15:30:26,817 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
    15:30:26,869 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.
    15:30:26,871 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@47f6473 - Registering current configuration as safe fallback point
    15:30:26,929 |-WARN in Logger[org.springframework.core.env.StandardEnvironment] - No appenders present in context [default] for logger [org.springframework.core.env.StandardEnvironment].
    这是BeanFactoryPostProcessor实现类构造器!!
    BeanFactoryPostProcessor调用postProcessBeanFactory方法
    这是BeanPostProcessor实现类构造器!!
    这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!
    InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法
    【构造器】调用Person的构造器实例化
    InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法
    【注入属性】注入属性name
    【注入属性】注入属性address
    【注入属性】注入属性age
    【BeanNameAware接口】调用BeanNameAware.setBeanName()
    【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()
    BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改!
    【InitializingBean接口】调用InitializingBean.afterPropertiesSet()
    【init-method】调用<bean>的init-method属性指定的初始化方法
    BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改!
    InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法
    容器初始化成功
    Person{name='尚硅谷', address='武汉', age=25, beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@694e1548: defining beans [person,beanPostProcessor,instantiationAwareBeanPostProcessor,beanFactoryPostProcessor]; root of factory hierarchy, beanName='person'}
    现在开始关闭容器!
    【DiposibleBean接口】调用DiposibleBean.destory()
    【destroy-method】调用<bean>的destroy-method属性指定的初始化方法
    

    相关文章

      网友评论

          本文标题:Java面试题:Spring Bean的生命周期

          本文链接:https://www.haomeiwen.com/subject/tjocfrtx.html