欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于Springboot的擴展點DisposableBean的原理解析

 更新時間:2023年05月19日 11:35:11   作者:凡夫販夫  
這篇文章主要介紹了關(guān)于Springboot的擴展點DisposableBean的原理解析,DisposableBean是一個接口,為Spring bean提供了一種釋放資源的方式 ,只有一個擴展方法destroy(),需要的朋友可以參考下

前言

DisposableBean,是在Spring容器關(guān)閉的時候預(yù)留的一個擴展點,從業(yè)務(wù)開發(fā)的角度來看,基本上是用不到的,但是Spring容器從啟動到關(guān)閉,是Spring Bean生命周期里一個繞不開的節(jié)點,因此還是有必要學習一下,以便對Spring能有一個更加全面的認識。

功能特性

1、DisposableBean是一個接口,為Spring bean提供了一種釋放資源的方式 ,只有一個擴展方法destroy();

2、實現(xiàn)DisposableBean接口,并重寫destroy(),可以在Spring容器銷毀bean的時候獲得一次回調(diào);

3、destroy()的回調(diào)執(zhí)行時機是Spring容器關(guān)閉,需要銷毀所有的bean時;

實現(xiàn)方式

與InitializingBean比較類似的是,InitializingBean#afterPropertiesSet()是在bean初始化的時候觸發(fā)執(zhí)行,DisposableBean#destroy()是在bean被銷毀的時候觸發(fā)執(zhí)行,這里結(jié)合Springboot擴展點之InitializingBean,用一個示例分析一下DisposableBean擴展接口的相關(guān)特性:

1、定義Dog類,實現(xiàn)InitializingBean、DisposableBean接口,并重寫afterPropertiesSet()、destroy()

@Slf4j
public class Dog implements InitializingBean, DisposableBean {
    private String name = "wang cai";
    private Food food;
    public Dog() {
        log.info("----Dog的無參構(gòu)造方法被執(zhí)行");
    }
    @Autowired
    public void setFood(Food food) {
        this.food = food;
        log.info("----dog的food屬性被注入");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("----com.fanfu.entity.Dog.afterPropertiesSet觸發(fā)執(zhí)行");
    }
    public void myInitMethod() {
        log.info("----com.fanfu.entity.Dog.myInitMethod觸發(fā)執(zhí)行");
    }
    @Override
    public void destroy() throws Exception {
        log.info("----com.fanfu.entity.Dog.destroy觸發(fā)執(zhí)行");
    }
}

2、單元測試也比較簡單,先啟動Spring容器,然后再優(yōu)雅地關(guān)閉;

  @Test
    public void test5(){
        log.info("----單元測試執(zhí)行開始");
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
        log.info("----開始關(guān)閉Spring容器");
        context.registerShutdownHook();
        log.info("----Spring容器已經(jīng)關(guān)閉完成");
        log.info("----單元測試執(zhí)行完畢");
    }

單元測試執(zhí)行結(jié)果:

從單元測試的執(zhí)行結(jié)果來看,Spring容器關(guān)閉后,會觸發(fā)執(zhí)行DisposableBean#destroy()擴展方法的執(zhí)行,所以如果我們的業(yè)務(wù)開發(fā)中,如果某些Bean在容器關(guān)閉后,需要做一些釋放業(yè)務(wù)資源之類的操作,就能用到這個擴展點了。有的小伙伴也許會有疑問:上面為什么單元測試執(zhí)行完了,才觸發(fā)Dog.destroy()方法執(zhí)行的?其實是這樣的,你仔細觀察會發(fā)現(xiàn),觸發(fā)Dog.destroy()方法執(zhí)行并不是主線程,而是叫做SpringContextShutdownHook的線程,這里用到了多線程技術(shù),單元測試執(zhí)行完了,才觸發(fā)Dog.destroy()方法執(zhí)行是多線程異步執(zhí)行的原因。

@Override
public void registerShutdownHook() {
   if (this.shutdownHook == null) {
      // 多線程執(zhí)行容器關(guān)閉的操作,主要邏輯在doClose()
      this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
         @Override
         public void run() {
            synchronized (startupShutdownMonitor) {
               doClose();
            }
         }
      };
      Runtime.getRuntime().addShutdownHook(this.shutdownHook);
   }
}

工作原理

從實現(xiàn)方式示例中,可以了解Spring容器關(guān)閉時,使用了多線程技術(shù)調(diào)用了doClose()來完成相關(guān)操作,然后觸發(fā)了DisposableBean#destroy()擴展方法的執(zhí)行。

doClose()中的邏輯也相對簡單,先發(fā)布一個ContextClosedEvent事件,告訴所有監(jiān)聽這個事件的監(jiān)聽器,馬上要關(guān)閉Spring容器了,這里其實也是一個擴展點,即通過Springboot的事件監(jiān)聽機制,也可以在Spring容器關(guān)閉的時候自定義一些操作;

緊接著停止Spring bean生命周期里的所有bean,銷毀Spring容器內(nèi)所有緩存的單例bean,Dog類就在銷毀之列,實際上Dog.destroy()方法執(zhí)行時機就在這;

最后才是真正的開始Spring容器的關(guān)閉;

protected void doClose() {
   // Check whether an actual close attempt is necessary...
   if (this.active.get() && this.closed.compareAndSet(false, true)) {
      if (logger.isDebugEnabled()) {
         logger.debug("Closing " + this);
      }
      LiveBeansView.unregisterApplicationContext(this);
      try {
         // Spring容器關(guān)閉的時候,會發(fā)布一個ContextClosedEvent事件
         publishEvent(new ContextClosedEvent(this));
      }
      catch (Throwable ex) {
         logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
      }
      // 停止Spring bean生命周期里的所有bean
      if (this.lifecycleProcessor != null) {
         try {
            this.lifecycleProcessor.onClose();
         }
         catch (Throwable ex) {
            logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
         }
      }
      //銷毀Spring容器內(nèi)所有緩存的單例bean
      destroyBeans();
      // 關(guān)閉Spring容器
      closeBeanFactory();
      onClose();
      if (this.earlyApplicationListeners != null) {
         this.applicationListeners.clear();
         this.applicationListeners.addAll(this.earlyApplicationListeners);
      }
      this.active.set(false);
   }
}

順著destroyBeans()繼續(xù)往執(zhí)行,在DefaultSingletonBeanRegistry#destroySingletons中,找到了觸發(fā)Dog.destroy()執(zhí)行的位置

public void destroySingletons() {
   if (logger.isTraceEnabled()) {
      logger.trace("Destroying singletons in " + this);
   }
   synchronized (this.singletonObjects) {
      this.singletonsCurrentlyInDestruction = true;
   }
   String[] disposableBeanNames;
   //所有DisposableBean的實現(xiàn)類都已經(jīng)在disposableBeans緩存
   synchronized (this.disposableBeans) {
      disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
   }
   //這里真接遍歷一遍調(diào)用,樸實無華
   for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
      destroySingleton(disposableBeanNames[i]);
   }
   this.containedBeanMap.clear();
   this.dependentBeanMap.clear();
   this.dependenciesForBeanMap.clear();
   clearSingletonCache();
}

總結(jié)

仔細琢磨一翻會發(fā)現(xiàn),DisposableBean這個擴展點很簡單,似乎沒什么用,只有一個擴展方法destroy(),其觸發(fā)時機也是在Spring容器關(guān)閉、銷毀bean的時候 ,但很關(guān)鍵。你想呀,我們使用Springboot作為項目的開發(fā)框架,業(yè)務(wù)實際上是跑在Spring容器里的,如果Spring容器關(guān)閉的時候,業(yè)務(wù)還正在執(zhí)行,這不是要出大亂子嗎?所以你說這個接口有用沒?肯定有用呀,優(yōu)雅安全的做法就是,在Spring容器關(guān)閉,通過這個擴展接口,提前安排好相關(guān)的業(yè)務(wù)資源釋放,防止出現(xiàn)一些不可控的業(yè)務(wù)錯誤。

到此這篇關(guān)于關(guān)于Springboot的擴展點DisposableBean的原理解析的文章就介紹到這了,更多相關(guān)Springboot擴展點DisposableBean內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺析Java中的訪問控制權(quán)限

    淺析Java中的訪問控制權(quán)限

    這篇文章主要介紹了淺析Java中的訪問控制權(quán)限,在Java中,提供了四種訪問權(quán)限控制,分別是默認訪問權(quán)限、public、private以及protected,感興趣的小伙伴們可以參考一下
    2016-02-02
  • IntelliJ?IDEA?2022.1.1創(chuàng)建java項目的詳細方法步驟

    IntelliJ?IDEA?2022.1.1創(chuàng)建java項目的詳細方法步驟

    最近安裝了IntelliJ IDEA 2022.1.1,發(fā)現(xiàn)新版本的窗口還有些變化的,所以下面這篇文章主要給大家介紹了關(guān)于IntelliJ?IDEA?2022.1.1創(chuàng)建java項目的詳細方法步驟,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-07-07
  • Spring中基于xml的AOP的詳細步驟

    Spring中基于xml的AOP的詳細步驟

    這篇文章主要介紹了Spring中基于xml的AOP的詳細步驟,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • Spring基于注解配置AOP詳解

    Spring基于注解配置AOP詳解

    這篇文章主要介紹了Spring基于注解配置AOP詳解,Spring 的 AOP 功能是基于 AspectJ 實現(xiàn)的,支持使用注解聲明式定義 AOP 切面,Spring 基于注解配置 AOP 需要啟用 AspectJ 自動代理功能,需要的朋友可以參考下
    2023-09-09
  • 如何使用try-with-resource機制關(guān)閉連接

    如何使用try-with-resource機制關(guān)閉連接

    這篇文章主要介紹了使用try-with-resource機制關(guān)閉連接的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Springboot Thymeleaf實現(xiàn)HTML屬性設(shè)置

    Springboot Thymeleaf實現(xiàn)HTML屬性設(shè)置

    這篇文章主要介紹了Springboot Thymeleaf實現(xiàn)HTML屬性設(shè)置,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2007-11-11
  • SpringBoot如何使用@Aspect注解實現(xiàn)AOP

    SpringBoot如何使用@Aspect注解實現(xiàn)AOP

    這篇文章主要介紹了SpringBoot如何使用@Aspect注解實現(xiàn)AOP問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Spring核心IoC容器的依賴注入接口和層級包命名規(guī)范

    Spring核心IoC容器的依賴注入接口和層級包命名規(guī)范

    這篇文章主要介紹了Spring核心IoC容器的依賴注入接口和層級包命名規(guī)范,IOC又名控制反轉(zhuǎn),把對象創(chuàng)建和對象之間的調(diào)用過程,交給Spring進行管理,目的是為了降低耦合度,需要的朋友可以參考下
    2023-05-05
  • Java 內(nèi)存安全問題的注意事項

    Java 內(nèi)存安全問題的注意事項

    內(nèi)存安全問題是每個程序員開發(fā)時都需要面對的問題,本文介紹了JVM管理內(nèi)存的原理以及內(nèi)存安全問題需要注意的地方,有此需求的朋友可以參考下本文
    2021-06-06
  • Java注解之Retention、Documented、Inherited介紹

    Java注解之Retention、Documented、Inherited介紹

    這篇文章主要介紹了Java注解之Retention、Documented、Inherited注解介紹,本文內(nèi)容和相關(guān)文章是系列文章,需要的朋友可以參考下
    2014-09-09

最新評論