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


    摘要:如果熟悉Spring 中 Bean的生命周期,可以加深对Spring的认知,故综述一下Bean的生命周期。

    前言

      Spring中Bean的生命周期是找工作的时候会被问到的高频面试题,主要用于考察应聘者对Spring是否熟悉,工作中很少用到其中的内容。

      配置在Spring中的Bean在Spring容器中从加载到销毁会经历哪些过程呢?如果实现一些特定的Spring接口,这些特定接口的方法会在什么时候被调用呢?

      Bean初始化入口:以Spring Boot项目为例,在项目启动的时候,SpringApplication的run方法会调用函数refreshContext(ApplicationContext applicationContext),此函数最终调用 AbstractApplicationContext 类的refresh()方法以刷新容器,创建Bean。refresh()方法源码如下,如果为了面试,可以跳过(嘻嘻):

    
    	/** Synchronization monitor for the "refresh" and "destroy". */
    	private final Object startupShutdownMonitor = new Object();
    	 @Override
    	public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
     
                // 设置Spring容器的启动时间,撤销关闭状态,开启活跃状态
                // Prepare this context for refreshing.
    			prepareRefresh(); 
                // 得到BeanFactory
                // Tell the subclass to refresh the internal bean factory.
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 
                // 给BeanFactory设置一些属性
                // Prepare the bean factory for use in this context.
    			prepareBeanFactory(beanFactory); 
    			try { 
                    // 后置处理BeanFactory
    				postProcessBeanFactory(beanFactory); 
                    // 注册并调用BeanFactoryPostProcessor后置处理器
                    // 其中ConfigurationClassPostProcessor这个后置处理器会扫描Bean并且注册到容器中
    //这个方法做了很多事,Spring IOC容器初始化中的资源定位、BeanDefinition载入和解析、BeanDefinition注册都是这个方法完成的
    				invokeBeanFactoryPostProcessors(beanFactory); 
                    // 注册BeanPostProcessor后置处理器,这里的后置处理器在下方实例化Bean方法中会用到
    				registerBeanPostProcessors(beanFactory); 
    				initMessageSource();
     
                    // 初始化ApplicationEventMulticaster
    				initApplicationEventMulticaster(); 
                    //创建tomcat启动了Tomcat的Server、Service、Container、Engine、Realm、Pipeline、Value、MapperListerner
                    onRefresh(); 
                    // 注册监听器
    				registerListeners(); 
                    // 实例化非懒加载的Bean
    				finishBeanFactoryInitialization(beanFactory); 
                    // 启动tomcat的Connector
    				finishRefresh();
    			} catch (BeansException ex) {
    				if (logger.isWarnEnabled()) {
    					logger.warn("Exception encountered during context initialization - " +	 "cancelling refresh attempt: " + ex);
    				}
     
    				// Destroy already created singletons to avoid dangling resources.
    				destroyBeans(); 
    				// Reset 'active' flag.
    				cancelRefresh(ex); 
    				// Propagate exception to caller.
    				throw ex;
    			} finally {
    				// Reset common introspection caches in Spring's core, since we
    				// might not ever need metadata for singleton beans anymore...
    				resetCommonCaches();
    			}
    		}
    	}
    

    Bean的生命周期

      一个Bean从创建到销毁,如果是用BeanFactory来生成和管理Bean的话,主要会经历四个过程:实例化 -> 属性赋值 -> 初始化 -> 销毁。

    • 实例化 Instantiation
    • 属性赋值 Populate
    • 初始化 Initialization
    • 销毁 Destruction

      spring Bean加载的过程主要就是执行AbstractApplicationContext类中的refresh方法。完整生命周期如下图所示:

    1. Bean实例化
      也就是我们常说的new,调用Bean的构造函数或者工厂方法。

    2. 属性赋值
      对Bean的成员变量赋值。使用依赖注入,Spring按照Bean定义信息配置Bean所有属性。

    3. BeanNameAware的setBeanName()
      如果Bean类有实现org.springframework.beans.BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。

    4. BeanFactoryAware的setBeanFactory()
      如果Bean类有实现org.springframework.beans.factory.BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。

    5. 实现了ApplicationContextAware接口
      使用ApplicationContext来生成并管理Bean的话,才有此步;否则,没有。
      如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现上一步的内容,但比上一步更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);

    6. BeanPostProcessors的ProcessBeforeInitialization()
      如果有org.springframework.beans.factory.config.BeanPostProcessors和Bean关联,那么其postProcessBeforeInitialization()方法将被将被调用。

    7. initializingBean的afterPropertiesSet():
      如果Bean类已实现org.springframework.beans.factory.InitializingBean接口,则执行他的afterProPertiesSet()方法。

    8. Bean定义文件中定义init-method
      如果在Bean定义文件中使用“init-method”属性设定方法名称,如下:
      <bean id="demoBean" class="com.yangsq.bean.DemoBean" init-method="initMethod">
        .......
       </bean>
      则会执行initMethod()方法,注意,这个方法是不带参数的。

    9. BeanPostProcessors的ProcessaAfterInitialization()
      容器中如果有实现org.springframework.beans.factory.BeanPostProcessors接口的实例,则Bean在初始化之前都会执行这个实例的processAfterInitialization()方法。

    10. Bean处于可以使用的状态。
      此时,Bean已经可以被应用系统使用,并且将保留在BeanFactory中直到它不再被使用。

    11. Spring容器关闭。
      下面介绍销毁流程。

    12. DisposableBean的destroy()
      容器关闭时,如果Bean类实现了org.springframework.beans.factory.DisposableBean接口,则执行它的destroy()方法。

    13. Bean定义文件中定义destroy-method
      在容器关闭时,可以在Bean定义文件中使用"destroy-method"属性设定方法名称。例如:
      <bean id="demoBean" class="com.yangsq.bean.DemoBean" destory-method="destroyMethod">
        .......
      </bean>
      这时会执行destroyMethod()方法,注意,这个方法是不带参数的。

    小结

      在Spring框架中,一旦把一个bean纳入到Spring IoC容器之中,这个bean的生命周期就会交由容器进行管理,一般担当管理者角色的是BeanFactory或ApplicationContext。认识一下Bean的生命周期活动,对更好的利用它有很大的帮助。

    Reference


      读后有收获,小礼物走一走,请作者喝咖啡。

    赞赏支持

  • 相关阅读:
    EF Core 小技巧:迁移已经应用到数据库,如何进行迁移回退操作?
    ABP Framework 5.0 RC.1 新特性和变更说明
    OI迷惑行为大赏【目前较少,持续更新中】
    【比赛日志】APIO2020(2020.08.15)
    【好题】【IPSC2003】 Got Root? 无向图删边游戏
    [HNOI2019] 校园旅行 —— 一个边界数据
    【题解】JOISC 2020 Day 3 stray
    ExtJS学习:MVC模式案例(四) 林枫705
    ExtJS学习:MVC模式案例(三) 林枫705
    ExtJS学习:MVC模式案例(二) 林枫705
  • 原文地址:https://www.cnblogs.com/east7/p/14563676.html
Copyright © 2020-2023  润新知