最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

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

功能特性

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

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

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

實(shí)現(xiàn)方式

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

1、定義Dog類,實(shí)現(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、單元測試也比較簡單,先啟動(dòng)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()擴(kuò)展方法的執(zhí)行,所以如果我們的業(yè)務(wù)開發(fā)中,如果某些Bean在容器關(guān)閉后,需要做一些釋放業(yè)務(wù)資源之類的操作,就能用到這個(gè)擴(kuò)展點(diǎn)了。有的小伙伴也許會有疑問:上面為什么單元測試執(zhí)行完了,才觸發(fā)Dog.destroy()方法執(zhí)行的?其實(shí)是這樣的,你仔細(xì)觀察會發(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);
   }
}

工作原理

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

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

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

最后才是真正的開始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)閉的時(shí)候,會發(fā)布一個(gè)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的實(shí)現(xiàn)類都已經(jīng)在disposableBeans緩存
   synchronized (this.disposableBeans) {
      disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
   }
   //這里真接遍歷一遍調(diào)用,樸實(shí)無華
   for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
      destroySingleton(disposableBeanNames[i]);
   }
   this.containedBeanMap.clear();
   this.dependentBeanMap.clear();
   this.dependenciesForBeanMap.clear();
   clearSingletonCache();
}

總結(jié)

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

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

相關(guān)文章

  • MyBatis-Plus中如何配置加密功能(使用AES算法)

    MyBatis-Plus中如何配置加密功能(使用AES算法)

    本文將詳細(xì)介紹如何實(shí)現(xiàn) MyBatis-Plus 中的配置加密功能,并給出相應(yīng)的代碼示例,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • Java+mysql用戶注冊登錄功能

    Java+mysql用戶注冊登錄功能

    這篇文章主要為大家詳細(xì)介紹了Java結(jié)合mysql實(shí)現(xiàn)用戶注冊登錄功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Java編程實(shí)現(xiàn)判斷網(wǎng)上鄰居文件是否存在的方法

    Java編程實(shí)現(xiàn)判斷網(wǎng)上鄰居文件是否存在的方法

    這篇文章主要介紹了Java編程實(shí)現(xiàn)判斷網(wǎng)上鄰居文件是否存在的方法,涉及Java針對路徑轉(zhuǎn)換及字符串操作的相關(guān)技巧,需要的朋友可以參考下
    2015-10-10
  • 詳解Maven多模塊打包遇到的問題解決方法

    詳解Maven多模塊打包遇到的問題解決方法

    這篇文章主要介紹了詳解Maven多模塊打包遇到的問題解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(27)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(27)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-07-07
  • 詳解Java去除json數(shù)據(jù)中的null空值問題

    詳解Java去除json數(shù)據(jù)中的null空值問題

    這篇文章主要介紹了詳解Java去除json數(shù)據(jù)中的null空值問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • SpringBoot?中使用?Validation?校驗(yàn)參數(shù)的方法詳解

    SpringBoot?中使用?Validation?校驗(yàn)參數(shù)的方法詳解

    Validation?是用于檢查程序代碼中參數(shù)的有效性的框架,作為?Spring?框架中的一個(gè)參數(shù)校驗(yàn)工具,集成在?spring-context?包中,這篇文章主要介紹了SpringBoot?中使用?Validation?校驗(yàn)參數(shù),需要的朋友可以參考下
    2022-05-05
  • MyBatis連接數(shù)據(jù)庫配置的基本步驟和機(jī)制

    MyBatis連接數(shù)據(jù)庫配置的基本步驟和機(jī)制

    MyBatis 是一個(gè)流行的持久層框架,它通過使用XML或注解的方式將SQL語句、存儲過程和Java方法進(jìn)行綁定,從而避免了手寫大量的JDBC代碼和手動(dòng)設(shè)置參數(shù)與結(jié)果集,本文給大家介紹了MyBatis連接數(shù)據(jù)庫配置的基本步驟和機(jī)制,需要的朋友可以參考下
    2024-05-05
  • 如何在IDEA啟動(dòng)多個(gè)Spring Boot工程實(shí)例(圖文)

    如何在IDEA啟動(dòng)多個(gè)Spring Boot工程實(shí)例(圖文)

    這篇文章主要介紹了如何在IDEA啟動(dòng)多個(gè)Spring Boot工程實(shí)例(圖文),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java使用Jdbc連接Oracle執(zhí)行簡單查詢操作示例

    Java使用Jdbc連接Oracle執(zhí)行簡單查詢操作示例

    這篇文章主要介紹了Java使用Jdbc連接Oracle執(zhí)行簡單查詢操作,結(jié)合實(shí)例形式詳細(xì)分析了java基于jdbc實(shí)現(xiàn)Oracle數(shù)據(jù)庫的連接與查詢相關(guān)操作技巧,需要的朋友可以參考下
    2019-09-09

最新評論

刚察县| 罗山县| 和田市| 新沂市| 嵩明县| 兴海县| 克东县| 特克斯县| 中卫市| 宝兴县| 左权县| 和顺县| 长泰县| 田林县| 鸡西市| 台北市| 常熟市| 宁晋县| 正蓝旗| 定兴县| 镶黄旗| 离岛区| 财经| 比如县| 镇原县| 洛扎县| 思茅市| 西安市| 新郑市| 繁峙县| 长葛市| 营口市| 保靖县| 微博| 天长市| 容城县| 阿图什市| 永川市| 阜新市| 瑞金市| 朝阳市|