Spring扩展接口BeanFactoryAware,InitializingBean,DisposableBean与bean的生命周期

一、介绍

从一张spring经典bean的生命周期图说起:

接口介绍:

  • xxAware接口:包含常见的BeanFactoryAware、BeanFactoryAware、ApplicationContextAware
  • BeanPostProcessor接口:方法postProcessBeforeInitialization()、postProcessAfterInitialization(),用于在bean初始化时进行前置、后置处理。
  • InitializingBean接口:方法afterPropertiesSet(),顾名思义在Properties配置文件初始化之后调用。
  • DisposableBean接口:方法destroy(),bean的生命周期结束前调用。
  • init-method方法:初始化方法
  • destroy方法:销毁方法

 二、示例

这里整一个demo,如下所示:

BeanFactoryAware,InitializingBean,DisposableBean接口实现类:

 1 public class SpringStartTestBean implements BeanFactoryAware,InitializingBean,DisposableBean {
 2 
 3     @Override
 4     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
 5         System.out.println("BeanFactoryAware.setBeanFactory() running");
 6     }
 7 
 8     @Override
 9     public void destroy() throws Exception {
10         System.out.println("DisposableBean.destroy() running");
11     }
12 
13     @Override
14     public void afterPropertiesSet() throws Exception {
15         System.out.println("InitializingBean.afterPropertiesSet() running");
16     }
17 
18     public void initMethod(){
19         System.out.println("initMethod() running");
20     }
21 
22     public void destroyMethod(){
23         System.out.println("destroyMethod() running");
24     }
25 }

BeanPostProcessor接口实现类:

 1 public class TestBeanPostProcessor implements BeanPostProcessor {
 2     @Override
 3     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 4         System.out.println("BeanPostProcessor.postProcessBeforeInitialization() running|beanName="+beanName);
 5         return null;
 6     }
 7 
 8     @Override
 9     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
10         System.out.println("BeanPostProcessor.postProcessAfterInitialization() running|beanName="+beanName);
11         return null;
12     }
13 }

spring配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">
 
    <bean id="stringStartTest" class="com.spring.test.SpringStartTestBean" init-method="initMethod" destroy-method="destroyMethod"/>

    <bean id="testBeanPostProcessor" class="com.spring.test.TestBeanPostProcessor" />
</beans>

注:这里可能有小伙伴会问,为什么BeanPostProcessor接口要单独整一个实现类,用第一个类不可以吗?这是因为BeanPostProcessor接口实现类是所有bean共有的,每个bean初始化前后都会调BeanPostProcessor实现类的方法,因此放到某个具体的bean中都不合适。

启动类:

1 public class Test {
2     
3     public static void main(String[] args) {
4         ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
5         ((ClassPathXmlApplicationContext) context).close();
6     }
7 
8 }

运行结果:

 可见,实现的各个接口方法调用顺序符合原图。

注:

  • destroy-method一般作为DisposableBean.destory()方法的替代,二者功能等效,因为DisposableBean.destory()接口实现依赖于Spring,为与Spring解耦可以用destroy-method;
  • 两个destroy()方法运行有两个前提:
    • context关闭,如我们实例中的((ClassPathXmlApplicationContext) context).close();
    • bean的scope为singleton,即spring只销毁单例的bean

 三、源码分析

1、bean的创建

前面的跳过,直接通过refash()方法往下调用:

ApplicationContext.refresh()

  ->ApplicationContext.registerBeanPostProcessors()

    ->PostProcessorRegistrationDelegate.registerBeanPostProcessors()

      ->AbstractBeanFactory.getBean()->......

        ->AbstractAutowireCapableBeanFactory.initializeBean()

  

 在AbstractAutowireCapableBeanFactory.initializeBean()方法中:

如上所示:

invokeAwareMethods()方法调用各个xxAware接口的实现方法,然后调用BeanPostProcessor接口实现的postProcessBeforeInitialization()方法,继而调用init-method指定的方法,最后调用BeanPostProcessor接口实现的postProcessAfterInitialization()方法.

而InitializingBean的接口实现方法调用是在方法invokeInitMethod()中,调用init-method之前:

 2、bean的销毁

spring中bean的销毁由context的销毁触发的,我们从ClassPathXmlApplicationContext.close()方法进入:

AbstractApplicationContext.close()

  ->AbstractApplicationContext.doClose()

    ->AbstractApplicationContext.destroyBeans()

      ->DefaultListableBeanFactory.destroySingletons()

        ->DefaultListableBeanRegistry.destroySingletons()

          ->DefaultListableBeanRegistry.destroySingleton()

            ->DefaultListableBeanRegistry.destroyBean()

              ->DisposableBeanAdapter.destroy()

在DisposableBeanAdapter.destroy()方法中:

 1     @Override
 2     public void destroy() {
 3         if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
 4             for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
 5                 processor.postProcessBeforeDestruction(this.bean, this.beanName);
 6             }
 7         }
 8 
 9         if (this.invokeDisposableBean) {
10             if (logger.isTraceEnabled()) {
11                 logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
12             }
13             try {
14                 if (System.getSecurityManager() != null) {
15                     AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
16                         ((DisposableBean) this.bean).destroy();
17                         return null;
18                     }, this.acc);
19                 }
20                 else {
21                     ((DisposableBean) this.bean).destroy();//调用DisposableBean接口实现类的destroy()方法
22                 }
23             }
24             catch (Throwable ex) {
25                 String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
26                 if (logger.isDebugEnabled()) {
27                     logger.warn(msg, ex);
28                 }
29                 else {
30                     logger.warn(msg + ": " + ex);
31                 }
32             }
33         }
34 
35         if (this.destroyMethod != null) {
36             invokeCustomDestroyMethod(this.destroyMethod);//调用destory-Method指定的销毁方法
37         }
38         else if (this.destroyMethodName != null) {
39             Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
40             if (methodToInvoke != null) {
41                 invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
42             }
43         }
44     }

其中,第21行调用了DisposableBean接口实现类的destroy()方法,第36行调用了destroy-method指定的销毁方法。

四、拓展

在spring中我们可以手动调用xxApplicationContext.close()或xxBeanFactory.destroySingletons()来销毁单例的bean,但是如果在web容器或EJB容器中该如何销毁这些bean呢?直接调用xxApplicationContext.close()或xxBeanFactory.destroySingletons(),这可不够丝滑。

javax.servlet-api包已经为web容器准备好了,实现ServletContextListener接口:

1 public interface ServletContextListener extends EventListener {
2 
3     public void contextInitialized(ServletContextEvent sce);
4 
5     public void contextDestroyed(ServletContextEvent sce);
6 
7 }

可见,该接口只提供了两个方法:

contextInitialized():完成context初始化

contextDestroyed():完成context销毁

其中,context.close操作可以封装在contextDestroyed()方法的实现中。

在spring-web包中,已经提供了实现类ContextLoaderListener感兴趣的小伙伴可以看看具体实现。

 1 public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
 2 
 3     public ContextLoaderListener() {
 4     }
 5 
 6     public ContextLoaderListener(WebApplicationContext context) {
 7         super(context);
 8     }
 9 
10     @Override
11     public void contextInitialized(ServletContextEvent event) {
12         initWebApplicationContext(event.getServletContext());
13     }
14 
15
16     /**
17      * Close the root web application context.
18      */
19     @Override
20     public void contextDestroyed(ServletContextEvent event) {
21         closeWebApplicationContext(event.getServletContext());
22         ContextCleanupListener.cleanupAttributes(event.getServletContext());
23     }
24 
25 }

 

注:文中spring源码基于5.2.8.RELEASE

 

posted @ 2021-05-17 15:12  书剑江山  阅读(768)  评论(0)    收藏  举报