InitializingBean和DisposableBean


InitializingBean

記住一點:InitializingBean接口為bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是繼承該接口的子類,在初始化bean的時候會執行該方法。

下面看下簡單的例子:(環境是用Spring Boot搭建,直接用SpringtestApplication啟動即可

<bean id="myInitializingBean" class="com.paic.phssp.springtest.init.MyInitializingBean" init-method="testInit"></bean>

 

package com.paic.phssp.springtest.init;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * 繼承InitializingBean接口的類,在初始化bean的時候會執行該方法
 */
//@Component
public class MyInitializingBean implements InitializingBean {

    public MyInitializingBean() {
        System.out.println("MyInitializingBean....");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("ceshi MyInitializingBean>>>>>>>>>>>>>>>>>>>");
    }

    @PostConstruct  //功能上近似init-method,但加載時機不同
    public void test(){
        System.out.println("PostConstruct >>>>>>>>>>>>");
    }

    public void testInit(){
        System.out.println("ceshi init-method");
    }
}

 

結果:

MyInitializingBean....
PostConstruct >>>>>>>>>>>>
ceshi MyInitializingBean>>>>>>>>>>>>>>>>>>>
ceshi init-method

說明:

通過上述輸出結果,三者的先后順序也就一目了然了:

Constructor > @PostConstruct > InitializingBean > init-method

 

(1)通過查看spring的加載bean的源碼類(AbstractAutowireCapableBeanFactory)可看出其中奧妙:

AbstractAutowireCapableBeanFactory.invokeInitMethods

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
        boolean isInitializingBean = bean instanceof InitializingBean; if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }

            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged(() -> {
                        ((InitializingBean)bean).afterPropertiesSet();
                        return null;
                    }, this.getAccessControlContext());
                } catch (PrivilegedActionException var6) {
                    throw var6.getException();
                }
            } else {
                ((InitializingBean)bean).afterPropertiesSet();
            }
        }

        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) {
                this.invokeCustomInitMethod(beanName, bean, mbd);
            }
        }

    }

說明:

a、 spring為bean提供了兩種初始化bean的方式,實現InitializingBean接口,實現afterPropertiesSet方法,或者在配置文件中同過init-method指定,兩種方式可以同時使用
b、實現InitializingBean接口是直接調用afterPropertiesSet方法,比通過反射調用init-method指定的方法效率相對來說要高點。但是init-method方式消除了對spring的依賴
c、如果調用afterPropertiesSet方法時出錯,則不調用init-method指定的方法。
d、@PostConstruct注解后的方法在BeanPostProcessor前置處理器中就被執行了,所以當然要先於InitializingBean和init-method執行了。
 
下面看@PostConstruct加載過程,主要看CommonAnnotationBeanPostProcessor.class。看下面UML圖:
 

看下源碼:InitDestroyAnnotationBeanPostProcessor.class

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = this.findLifecycleMetadata(bean.getClass()); try {
        //利用反射,執行注解方法 metadata.invokeInitMethods(bean, beanName);
return bean; } catch (InvocationTargetException var5) { throw new BeanCreationException(beanName, "Invocation of init method failed", var5.getTargetException()); } catch (Throwable var6) { throw new BeanCreationException(beanName, "Failed to invoke init method", var6); } } private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata findLifecycleMetadata(Class<?> clazz) { if (this.lifecycleMetadataCache == null) { return this.buildLifecycleMetadata(clazz); } else { InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = (InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata)this.lifecycleMetadataCache.get(clazz); if (metadata == null) { Map var3 = this.lifecycleMetadataCache; synchronized(this.lifecycleMetadataCache) { metadata = (InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata)this.lifecycleMetadataCache.get(clazz); if (metadata == null) { metadata = this.buildLifecycleMetadata(clazz); this.lifecycleMetadataCache.put(clazz, metadata); } return metadata; } } else { return metadata; } } } private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata buildLifecycleMetadata(Class<?> clazz) { List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> initMethods = new ArrayList(); List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> destroyMethods = new ArrayList(); Class targetClass = clazz; do { List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currInitMethods = new ArrayList(); List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currDestroyMethods = new ArrayList(); ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
       //判斷是否是指定的注解類型
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) { InitDestroyAnnotationBeanPostProcessor.LifecycleElement element = new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method); currInitMethods.add(element); if (this.logger.isTraceEnabled()) { this.logger.trace("Found init method on class [" + clazz.getName() + "]: " + method); } } if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) { currDestroyMethods.add(new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method)); if (this.logger.isTraceEnabled()) { this.logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method); } } }); initMethods.addAll(0, currInitMethods); destroyMethods.addAll(currDestroyMethods); targetClass = targetClass.getSuperclass(); } while(targetClass != null && targetClass != Object.class); return new InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata(clazz, initMethods, destroyMethods); }

方法:buildLifecycleMetadata(),判斷是否是指定的注解類型,而這個屬性,在CommonAnnotationBeanPostProcessor.class構造方法中被初始化為PostConstruct。

public CommonAnnotationBeanPostProcessor() {
        this.setOrder(2147483644);
        this.setInitAnnotationType(PostConstruct.class); this.setDestroyAnnotationType(PreDestroy.class);
        this.ignoreResourceType("javax.xml.ws.WebServiceContext");
    }

那么問題來了,以上只能說明實現了BeanPostProcessor的postProcessBeforeInitialization()方法,不足說明@PostConstruct 先InitializingBean 。

再看AbstractAutowireCapableBeanFactory.class 的initializeBean()方法。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(() -> {
                this.invokeAwareMethods(beanName, bean);
                return null;
            }, this.getAccessControlContext());
        } else {
            this.invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        try {
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }

        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

這下明顯了,下面小結下:

BeanPostProcessor的實現類注冊到Spring IOC容器后,對於該Spring IOC容器所創建的每個bean實例在初始化方法(如afterPropertiesSet和任意已聲明的init方法)調用前,將會調用BeanPostProcessor中的postProcessBeforeInitialization方法,而在bean實例初始化方法調用完成后,則會調用BeanPostProcessor中的postProcessAfterInitialization方法,整個調用順序可以簡單示意如下:
--> Spring IOC容器實例化Bean
--> 調用BeanPostProcessor的postProcessBeforeInitialization方法 (@PostConstruct在此)
--> 調用bean實例的初始化方法(invokeInitMethods-> InitializingBean->init-method)
--> 調用BeanPostProcessor的postProcessAfterInitialization方法

參考: https://blog.csdn.net/zl834205311/article/details/78802584

DisposableBean
在Bean生命周期結束前調用destory()方法做一些收尾工作,亦可以使用destory-method。
前者與Spring耦合高,使用類型強轉.方法名(),效率高
后者耦合低,使用反射,效率相對低
 
首先看下入口代碼結構:

其中AbstractApplicationContext.refresh()

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            // 為刷新工作做一些當前上下文 context 上的准備工作
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            // ApplicationContext 實現了 BeanFactory 接口,但是並非直接作為 Bean 容器。
            // ApplicationContext 中真正直接作為 Bean 容器的是一個內部Bean工廠 BeanFactory,
            // 通過其方法 getBeanFactory() 得到,此方法在 AbstractApplicationContext 中
            // 被聲明為 abstract, 其實現要求由實現子類提供。下面的語句 obtainFreshBeanFactory()
            // 內部就是通過調用 getBeanFactory() 獲得這個內部 Bean 工廠的。
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
            // 准備當前上下文使用的Bean容器 BeanFactory,設置其標准上下文特征,比如類加載器等
            // 1. BeanFactory 的類加載器設置為當前上下文的類加載器
            // 2. BeanFactory 的Bean表達式解析器設置為 new StandardBeanExpressionResolver()
            // 3. BeanFactory 增加 BeanPostProcessror new ApplicationListenerDetector(this)
            // 4.三個單例Bean被注冊 : environment,systemProperties,systemEnvironment
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                // 在當前上下文使用的Bean容器BeanFactory的標准初始化完成后對其做一些修改。此時
                // 所有的Bean definition都已經加載但是還沒有 Bean 被創建。
                // 當前上下文使用的Bean容器 BeanFactory 的 post process
                // 1.當前上下文是 EmbeddedWebApplicationContext 時,
                // 這個步驟中會對 beanFactory 注冊一個 BeanPostProcessor :
                // WebApplicationContextServletContextAwareProcessor
                // 2.當前上下文是 AnnotationConfigEmbeddedWebApplicationContext 時,
                // 如果設置了 basePackages,
                // 這里會使用 AnnotatedBeanDefinitionReader掃描basePackages;
                // 如果設置了 annotatedClasses,
                // 這里會使用 ClassPathBeanDefinitionScanner登記annotatedClasses;
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                // 在 beanFactory 上調用 BeanFactoryPostProcessors, 
                // 當前上下文可能會有多個 BeanFactoryPostProcessor 需要應用在 beanFactory 上
                // ****************************************************************
                // 這里需要尤其注意區別 BeanFactoryPostProcessor 和 BeanPostProcessor
                // BeanFactoryPostProcessor : 作用在 Bean定義 上,用來定制修改 Bean定義
                // BeanPostProcessor :作用在 Bean實例 上,用來修改或者包裝 Bean實例
                // ****************************************************************
                
                // 該方法實際上將實現委托出去 : 
                // PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 注冊 BeanPostProcessor
                // 該步驟實際工作委托給工具類 PostProcessorRegistrationDelegate 的靜態方法
                // void registerBeanPostProcessors(
                //   ConfigurableListableBeanFactory beanFactory, 
                //   AbstractApplicationContext applicationContext)
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                // 初始化當前上下文ApplicationContext要使用的 事件多播器 
                // ApplicationEventMulticaster applicationEventMulticaster。
                // 
                // 如果容器中已經注冊類型為ApplicationEventMulticaster並且名稱為
                // applicationEventMulticaster 的Bean,則直接使用;否則,
                // 新建一個SimpleApplicationEventMulticaster實例並注冊到
                // Bean容器,Bean名稱使用 applicationEventMulticaster。
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                // AbstractApplicationContext 中 onRefresh() 方法實現為空,其目的就是
                // 留給實現子類一個機會做一些上下文相關的刷新工作。在一些特殊Bean初始化時,單
                // 例 singleton Bean 初始化之前該方法被調用。
                // 1. 當前上下文是 EmbeddedWebApplicationContext 時,該步驟會創建一個
                // 內置的 Servlet 容器, 具體參考 EmbeddedWebApplicationContext 的
                // 方法 void createEmbeddedServletContainer() 
                onRefresh();

                // Check for listener beans and register them.
                // 1. 將外部指定到當前上下文的 ApplicationListener 實例關聯到上下文多播器
                //    Q : 什么時候外部給當前上下文指定 ApplicationListener ?
                //    A : 舉例說明,Springboot 應用 SpringApplication 的情況下,是在
                //        prepareContext()結尾時SpringApplicationRunListeners的
                //        contextLoaded() 調用中發生的,此時正在廣播事件
                //        ApplicationPreparedEvent 
                // 2. 將實現了 ApplicationListener 接口的所有 Bean 關聯到上下文多播器
                // 3. 如果上下文屬性earlyApplicationEvents中有要通知的事件,廣播出去
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                // 完成 BeanFactory 的初始化工作
                // 1.BeanFactory凍結所有的Bean定義:不再可以修改或者做post process操作
                // 2.確保所有的non-lazy-init單例Bean被初始化,也包括FactoryBean
                // 3.如果所初始化的單例Bean實現了接口SmartInitializingSingleton,調用
                //   其方法 afterSingletonsInstantiated()
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                // 1. 初始化生命周期處理器 LifecycleProcessor, 使用已經存在的Bean或者
                //    一個新的DefaultLifecycleProcessor實例;
                // 2. 生命周期處理器 LifecycleProcessor 上傳播 refresh 事件
                // 3. 發布事件 ContextRefreshedEvent
                // 4. 如果存在 LiveBeansView MBean 的話,關聯到當前上下文
                // 當前上下文是EmbeddedWebApplicationContext的情況下,還會:
                // 5. 啟動EmbeddedServletContainer,比如啟動內置 tomcat容器
                // 6. 發布事件 EmbeddedServletContainerInitializedEvent
                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();
            }
        }
    }

org.springframework.context.support.AbstractApplicationContext#refresh的這一行代碼

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   refreshBeanFactory();
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
   }
   return beanFactory;
}

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory

 protected final void refreshBeanFactory() throws BeansException {
        if (this.hasBeanFactory()) {
            this.destroyBeans(); this.closeBeanFactory();
        }

        try {
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            this.loadBeanDefinitions(beanFactory);
            Object var2 = this.beanFactoryMonitor;
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

進入到這個方法org.springframework.context.support.AbstractApplicationContext#destroyBeans

protected void destroyBeans() {
        this.getBeanFactory().destroySingletons();
    }

org.springframework.beans.factory.support.DefaultListableBeanFactory#destroySingletons

@Override
   public void destroySingletons() {
      super.destroySingletons();
//    清除記錄的單例beanName的緩存
      this.manualSingletonNames.clear();
      clearByTypeCache();
   }
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingletons
@Override
   public void destroySingletons() {
      super.destroySingletons();
//    清空beanFactory緩存
      this.factoryBeanObjectCache.clear();
   }

public void destroySingletons() {
      if (logger.isDebugEnabled()) {
         logger.debug("Destroying singletons in " + this);
      }
//    這里使用ConcurrentHashMap本地緩存單例的bean實例,訪問次數比較多,提搞並發量
      synchronized (this.singletonObjects) {
         this.singletonsCurrentlyInDestruction = true;
      }

      String[] disposableBeanNames;
//    這里是用LinkedHashMap本地緩存銷毀的bean實例
      synchronized (this.disposableBeans) {
         disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
      }
      for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
//       銷毀單例的bean
         destroySingleton(disposableBeanNames[i]);
      }

      this.containedBeanMap.clear();
      this.dependentBeanMap.clear();
      this.dependenciesForBeanMap.clear();

//    同步清空緩存
      synchronized (this.singletonObjects) {
         this.singletonObjects.clear();
         this.singletonFactories.clear();
         this.earlySingletonObjects.clear();
         this.registeredSingletons.clear();
         this.singletonsCurrentlyInDestruction = false;
      }
   }

public void destroySingleton(String beanName) {
      // Remove a registered singleton of the given name, if any.刪除單例的bean,從本地緩存中刪除
      removeSingleton(beanName);

      // Destroy the corresponding DisposableBean instance.
      DisposableBean disposableBean;
      synchronized (this.disposableBeans) {
//       從本地緩存中刪除
         disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
      }
//    bean銷毀的邏輯
      destroyBean(beanName, disposableBean);
   }

protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
      // Trigger destruction of dependent beans first... 先觸發依賴的bean銷毀,從本地緩存中刪除
      Set<String> dependencies = this.dependentBeanMap.remove(beanName);
      if (dependencies != null) {
         if (logger.isDebugEnabled()) {
            logger.debug("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
         }
         for (String dependentBeanName : dependencies) {
//          這里用了一個遞歸刪除單例bean,當這個bean沒有依賴的bean要刪除的時候,遞歸結束
            destroySingleton(dependentBeanName);
         }
      }

      // Actually destroy the bean now... 這里開始刪除單例bean
      if (bean != null) {
         try {
//          bean可以實現DisposableBean這個接口,重寫父類的bean destory的方法
            bean.destroy();
         }
         catch (Throwable ex) {
            logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);
         }
      }

      // Trigger destruction of contained beans...從本地緩存中銷毀內部bean
      Set<String> containedBeans = this.containedBeanMap.remove(beanName);
      if (containedBeans != null) {
         for (String containedBeanName : containedBeans) {
//          這個地方還是遞歸調用,刪除單例bean,當這個bean沒有內部bean時遞歸結束
            destroySingleton(containedBeanName);
         }
      }

      // Remove destroyed bean from other beans' dependencies. 從其他bean依賴中刪除銷毀的bean
      synchronized (this.dependentBeanMap) {
         for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
            Map.Entry<String, Set<String>> entry = it.next();
            Set<String> dependenciesToClean = entry.getValue();
            dependenciesToClean.remove(beanName);
            if (dependenciesToClean.isEmpty()) {
               it.remove();
            }
         }
      }

      // Remove destroyed bean's prepared dependency information.刪除銷毀的bean准備的依賴信息
      this.dependenciesForBeanMap.remove(beanName);
   }
View Code
bean可以實現DisposableBean這個接口,重寫父類的bean destory的方法
 注意:此處destroyBean將會被字類重寫,用適配器模式銷毀
org.springframework.beans.factory.support.DisposableBeanAdapter#destroy
@Override
   public void destroy() {
//    執行beanPostProcessors,beanPostProcessors用對對bean的過程進行處理的抽象
      if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
         for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
//          在bean銷毀之前進行一些處理
            processor.postProcessBeforeDestruction(this.bean, this.beanName);
         }
      }

      if (this.invokeDisposableBean) {
         if (logger.isDebugEnabled()) {
            logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");
         }
         try {
            if (System.getSecurityManager() != null) {
               AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                  ((DisposableBean) bean).destroy();
                  return null;
               }, acc);
            }
            else {
//             bean實現DisposableBean接口的方式,注解調用子類destroy方法
               ((DisposableBean) bean).destroy();
            }
         }
         catch (Throwable ex) {
            String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
            if (logger.isDebugEnabled()) {
               logger.warn(msg, ex);
            }
            else {
               logger.warn(msg + ": " + ex);
            }
         }
      }

      if (this.destroyMethod != null) {
//       執行bean定義中指定的bean銷毀方法
         invokeCustomDestroyMethod(this.destroyMethod);
      }
      else if (this.destroyMethodName != null) {
         Method methodToCall = determineDestroyMethod(this.destroyMethodName);
         if (methodToCall != null) {
            invokeCustomDestroyMethod(methodToCall);
         }
      }
   }
View Code

 

具體結構如下:

 

參考:
https://my.oschina.net/u/3775437/blog/1810419
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM