zoukankan      html  css  js  c++  java
  • 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


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

    赞赏支持

  • 相关阅读:
    【乱侃】How do they look them ?
    【softeware】Messy code,some bug of Youdao notebook in EN win7
    【随谈】designing the login page of our project
    【web】Ad in security code, making good use of resource
    SQL数据库内存设置篇
    关系数据库的查询优化策略
    利用SQL未公开的存储过程实现分页
    sql语句总结
    sql中使用cmd命令注销登录用户
    SQLServer 分页存储过程
  • 原文地址:https://www.cnblogs.com/east7/p/14563676.html
Copyright © 2011-2022 走看看