自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

龍行有風(fēng),向虛擬機(jī)注冊(cè)鉤子,實(shí)現(xiàn)Bean對(duì)象的初始化和銷(xiāo)毀方法

云計(jì)算 虛擬化
本文主要完成了關(guān)于初始和銷(xiāo)毀在使用接口定義 implements InitializingBean, DisposableBean 和在spring.xml中配置 init-method="initDataMethod" destroy-method="destroyDataMethod" 的兩種具體在 AbstractAutowireCapableBeanFactory 完成初始方法和 AbstractApplicationContext 處理銷(xiāo)毀動(dòng)作的具體實(shí)現(xiàn)過(guò)程。

 [[407482]]

目錄

  • 一、前言
  • 二、目標(biāo)
  • 三、設(shè)計(jì)
  • 四、實(shí)現(xiàn)
    • 1. 工程結(jié)構(gòu)
    • 2. 定義初始化和銷(xiāo)毀方法的接口
    • 3. Bean屬性定義新增初始化和銷(xiāo)毀
    • 4. 執(zhí)行 Bean 對(duì)象的初始化方法
    • 5. 定義銷(xiāo)毀方法適配器(接口和配置)
    • 6. 創(chuàng)建Bean時(shí)注冊(cè)銷(xiāo)毀方法對(duì)象
    • 7. 虛擬機(jī)關(guān)閉鉤子注冊(cè)調(diào)用銷(xiāo)毀方法
  • 五、測(cè)試
    • 1. 事先準(zhǔn)備
    • 2. 配置文件
    • 3. 單元測(cè)試
  • 六、總結(jié)
  • 七、系列推薦

一、前言

有什么方式,能給代碼留條活路?

[[407483]]

有人說(shuō):人人都是產(chǎn)品經(jīng)理,那你知道嗎,人人也都可以是碼農(nóng)程序員!就像:

  • 編程就是;定義屬性、創(chuàng)建方法、調(diào)用展示
  • Java 和 PHP 就像男人和女人,前者在乎架構(gòu)化模塊后,后者在乎那個(gè)顏色我喜歡
  • 用心寫(xiě),但不要不做格式化
  • 初次和產(chǎn)品對(duì)接的三個(gè)寶:磚頭、鐵鍬、菜刀,分別保證有用、可用、好用
  • 從一行代碼到一噸代碼,開(kāi)發(fā)越來(lái)越難,壁壘也越來(lái)越高

其實(shí)學(xué)會(huì)寫(xiě)代碼并不難,但學(xué)會(huì)寫(xiě)好代碼卻很難。從易閱讀上來(lái)說(shuō)你的代碼要有準(zhǔn)確的命名和清晰的注釋、從易使用上來(lái)說(shuō)你的代碼要具備設(shè)計(jì)模式的包裝讓對(duì)外的服務(wù)調(diào)用更簡(jiǎn)單、從易擴(kuò)展上來(lái)說(shuō)你的代碼要做好業(yè)務(wù)和功能的實(shí)現(xiàn)分層。在易閱讀、易使用、易擴(kuò)展以及更多編碼規(guī)范的約束下,還需要在開(kāi)發(fā)完成上線(xiàn)后的交付結(jié)果上滿(mǎn)足;高可用、高性能、高并發(fā),與此同時(shí)你還會(huì)接到現(xiàn)有項(xiàng)目中層出不窮來(lái)自產(chǎn)品經(jīng)理新增的需求。

怎么辦?知道你在碼磚,不知道你在蓋哪個(gè)豬圈!

就算碼的磚是蓋的豬圈,也得因?yàn)樨i多擴(kuò)面積、改水槽、加飼料呀,所以根本沒(méi)法保證你寫(xiě)完的代碼就不會(huì)加需求。那么新加的需求如果是以破壞了你原有的封裝了非常完美500行的 ifelse 咋辦,拆了重蓋嗎?

兄嘚,給代碼留條活路吧!你的代碼用上了定義接口嗎、接口繼承接口嗎、接口由抽象類(lèi)實(shí)現(xiàn)嗎、類(lèi)繼承的類(lèi)實(shí)現(xiàn)了接口方法嗎,而這些操作都是為了讓你的程序邏輯做到分層、分區(qū)、分塊,把核心邏輯層和業(yè)務(wù)封裝層做好隔離,當(dāng)有業(yè)務(wù)變化時(shí)候,只需要做在業(yè)務(wù)層完成裝配,而底層的核心邏輯服務(wù)并不需要頻繁變化,它們所增加的接口也更原子化,不具備業(yè)務(wù)語(yǔ)意。所以這樣的實(shí)現(xiàn)方式才能給你的代碼留條活路。如果還不是太理解,可以多看看《重學(xué)Java設(shè)計(jì)模式》和現(xiàn)在編寫(xiě)的《手?jǐn)]Spring》,這里面都有大量的設(shè)計(jì)模式應(yīng)用實(shí)踐

二、目標(biāo)

當(dāng)我們的類(lèi)創(chuàng)建的 Bean 對(duì)象,交給 Spring 容器管理以后,這個(gè)類(lèi)對(duì)象就可以被賦予更多的使用能力。就像我們?cè)谏弦徽鹿?jié)已經(jīng)給類(lèi)對(duì)象添加了修改注冊(cè)Bean定義未實(shí)例化前的屬性信息修改和實(shí)例化過(guò)程中的前置和后置處理,這些額外能力的實(shí)現(xiàn),都可以讓我們對(duì)現(xiàn)有工程中的類(lèi)對(duì)象做相應(yīng)的擴(kuò)展處理。

那么除此之外我們還希望可以在 Bean 初始化過(guò)程,執(zhí)行一些操作。比如幫我們做一些數(shù)據(jù)的加載執(zhí)行,鏈接注冊(cè)中心暴漏RPC接口以及在Web程序關(guān)閉時(shí)執(zhí)行鏈接斷開(kāi),內(nèi)存銷(xiāo)毀等操作。如果說(shuō)沒(méi)有Spring我們也可以通過(guò)構(gòu)造函數(shù)、靜態(tài)方法以及手動(dòng)調(diào)用的方式實(shí)現(xiàn),但這樣的處理方式終究不如把諸如此類(lèi)的操作都交給 Spring 容器來(lái)管理更加合適。 因此你會(huì)看到到 spring.xml 中有如下操作:

需要滿(mǎn)足用戶(hù)可以在 xml 中配置初始化和銷(xiāo)毀的方法,也可以通過(guò)實(shí)現(xiàn)類(lèi)的方式處理,比如我們?cè)谑褂?Spring 時(shí)用到的 InitializingBean, DisposableBean 兩個(gè)接口。-其實(shí)還可以有一種是注解的方式處理初始化操作,不過(guò)目前還沒(méi)有實(shí)現(xiàn)到注解的邏輯,后續(xù)再完善此類(lèi)功能。

三、設(shè)計(jì)

可能面對(duì)像 Spring 這樣龐大的框架,對(duì)外暴露的接口定義使用或者xml配置,完成的一系列擴(kuò)展性操作,都讓 Spring 框架看上去很神秘。其實(shí)對(duì)于這樣在 Bean 容器初始化過(guò)程中額外添加的處理操作,無(wú)非就是預(yù)先執(zhí)行了一個(gè)定義好的接口方法或者是反射調(diào)用類(lèi)中xml中配置的方法,最終你只要按照接口定義實(shí)現(xiàn),就會(huì)有 Spring 容器在處理的過(guò)程中進(jìn)行調(diào)用而已。整體設(shè)計(jì)結(jié)構(gòu)如下圖:

  • 在 spring.xml 配置中添加 init-method、destroy-method 兩個(gè)注解,在配置文件加載的過(guò)程中,把注解配置一并定義到 BeanDefinition 的屬性當(dāng)中。這樣在 initializeBean 初始化操作的工程中,就可以通過(guò)反射的方式來(lái)調(diào)用配置在 Bean 定義屬性當(dāng)中的方法信息了。另外如果是接口實(shí)現(xiàn)的方式,那么直接可以通過(guò) Bean 對(duì)象調(diào)用對(duì)應(yīng)接口定義的方法即可,((InitializingBean) bean).afterPropertiesSet(),兩種方式達(dá)到的效果是一樣的。
  • 除了在初始化做的操作外,destroy-method 和 DisposableBean 接口的定義,都會(huì)在 Bean 對(duì)象初始化完成階段,執(zhí)行注冊(cè)銷(xiāo)毀方法的信息到 DefaultSingletonBeanRegistry 類(lèi)中的 disposableBeans 屬性里,這是為了后續(xù)統(tǒng)一進(jìn)行操作。這里還有一段適配器的使用,因?yàn)榉瓷湔{(diào)用和接口直接調(diào)用,是兩種方式。所以需要使用適配器進(jìn)行包裝,下文代碼講解中參考 DisposableBeanAdapter 的具體實(shí)現(xiàn)-關(guān)于銷(xiāo)毀方法需要在虛擬機(jī)執(zhí)行關(guān)閉之前進(jìn)行操作,所以這里需要用到一個(gè)注冊(cè)鉤子的操作,如:Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("close!"))); 這段代碼你可以執(zhí)行測(cè)試,另外你可以使用手動(dòng)調(diào)用 ApplicationContext.close 方法關(guān)閉容器。

四、實(shí)現(xiàn)

1. 工程結(jié)構(gòu)

  1. small-spring-step-07 
  2. └── src 
  3.     ├── main 
  4.     │   └── java 
  5.     │       └── cn.bugstack.springframework 
  6.     │           ├── beans 
  7.     │           │   ├── factory 
  8.     │           │   │   ├── factory 
  9.     │           │   │   │   ├── AutowireCapableBeanFactory.java 
  10.     │           │   │   │   ├── BeanDefinition.java 
  11.     │           │   │   │   ├── BeanFactoryPostProcessor.java 
  12.     │           │   │   │   ├── BeanPostProcessor.java 
  13.     │           │   │   │   ├── BeanReference.java 
  14.     │           │   │   │   ├── ConfigurableBeanFactory.java 
  15.     │           │   │   │   └── SingletonBeanRegistry.java 
  16.     │           │   │   ├── support 
  17.     │           │   │   │   ├── AbstractAutowireCapableBeanFactory.java 
  18.     │           │   │   │   ├── AbstractBeanDefinitionReader.java 
  19.     │           │   │   │   ├── AbstractBeanFactory.java 
  20.     │           │   │   │   ├── BeanDefinitionReader.java 
  21.     │           │   │   │   ├── BeanDefinitionRegistry.java 
  22.     │           │   │   │   ├── CglibSubclassingInstantiationStrategy.java 
  23.     │           │   │   │   ├── DefaultListableBeanFactory.java 
  24.     │           │   │   │   ├── DefaultSingletonBeanRegistry.java 
  25.     │           │   │   │   ├── DisposableBeanAdapter.java 
  26.     │           │   │   │   ├── InstantiationStrategy.java 
  27.     │           │   │   │   └── SimpleInstantiationStrategy.java   
  28.     │           │   │   ├── support 
  29.     │           │   │   │   └── XmlBeanDefinitionReader.java 
  30.     │           │   │   ├── BeanFactory.java 
  31.     │           │   │   ├── ConfigurableListableBeanFactory.java 
  32.     │           │   │   ├── DisposableBean.java 
  33.     │           │   │   ├── HierarchicalBeanFactory.java 
  34.     │           │   │   ├── InitializingBean.java 
  35.     │           │   │   └── ListableBeanFactory.java 
  36.     │           │   ├── BeansException.java 
  37.     │           │   ├── PropertyValue.java 
  38.     │           │   └── PropertyValues.java  
  39.     │           ├── context 
  40.     │           │   ├── support 
  41.     │           │   │   ├── AbstractApplicationContext.java  
  42.     │           │   │   ├── AbstractRefreshableApplicationContext.java  
  43.     │           │   │   ├── AbstractXmlApplicationContext.java  
  44.     │           │   │   └── ClassPathXmlApplicationContext.java  
  45.     │           │   ├── ApplicationContext.java  
  46.     │           │   └── ConfigurableApplicationContext.java 
  47.     │           ├── core.io 
  48.     │           │   ├── ClassPathResource.java  
  49.     │           │   ├── DefaultResourceLoader.java  
  50.     │           │   ├── FileSystemResource.java  
  51.     │           │   ├── Resource.java  
  52.     │           │   ├── ResourceLoader.java  
  53.     │           │   └── UrlResource.java 
  54.     │           └── utils 
  55.     │               └── ClassUtils.java 
  56.     └── test 
  57.         └── java 
  58.             └── cn.bugstack.springframework.test 
  59.                 ├── bean 
  60.                 │   ├── UserDao.java 
  61.                 │   └── UserService.java 
  62.                 └── ApiTest.java 

工程源碼:公眾號(hào)「bugstack蟲(chóng)洞?!?,回復(fù):Spring 專(zhuān)欄,獲取完整源碼

Spring 應(yīng)用上下文和對(duì)Bean對(duì)象擴(kuò)展機(jī)制的類(lèi)關(guān)系,如圖 8-4

圖 8-4

  • 以上整個(gè)類(lèi)圖結(jié)構(gòu)描述出來(lái)的就是本次新增 Bean 實(shí)例化過(guò)程中的初始化方法和銷(xiāo)毀方法。
  • 因?yàn)槲覀円还矊?shí)現(xiàn)了兩種方式的初始化和銷(xiāo)毀方法,xml配置和定義接口,所以這里既有 InitializingBean、DisposableBean 也有需要 XmlBeanDefinitionReader 加載 spring.xml 配置信息到 BeanDefinition 中。
  • 另外接口 ConfigurableBeanFactory 定義了 destroySingletons 銷(xiāo)毀方法,并由 AbstractBeanFactory 繼承的父類(lèi) DefaultSingletonBeanRegistry 實(shí)現(xiàn) ConfigurableBeanFactory 接口定義的 destroySingletons 方法。這種方式的設(shè)計(jì)可能數(shù)程序員是沒(méi)有用過(guò)的,都是用的誰(shuí)實(shí)現(xiàn)接口誰(shuí)完成實(shí)現(xiàn)類(lèi),而不是把實(shí)現(xiàn)接口的操作又交給繼承的父類(lèi)處理。所以這塊還是蠻有意思的,是一種不錯(cuò)的隔離分層服務(wù)的設(shè)計(jì)方式
  • 最后就是關(guān)于向虛擬機(jī)注冊(cè)鉤子,保證在虛擬機(jī)關(guān)閉之前,執(zhí)行銷(xiāo)毀操作。Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("close!")));

2. 定義初始化和銷(xiāo)毀方法的接口

cn.bugstack.springframework.beans.factory.InitializingBean

  1. public interface InitializingBean { 
  2.  
  3.     /** 
  4.      * Bean 處理了屬性填充后調(diào)用 
  5.      *  
  6.      * @throws Exception 
  7.      */ 
  8.     void afterPropertiesSet() throws Exception; 
  9.  

cn.bugstack.springframework.beans.factory.DisposableBean

  1. public interface DisposableBean { 
  2.  
  3.     void destroy() throws Exception; 
  4.  
  • InitializingBean、DisposableBean,兩個(gè)接口方法還是比較常用的,在一些需要結(jié)合 Spring 實(shí)現(xiàn)的組件中,經(jīng)常會(huì)使用這兩個(gè)方法來(lái)做一些參數(shù)的初始化和銷(xiāo)毀操作。比如接口暴漏、數(shù)據(jù)庫(kù)數(shù)據(jù)讀取、配置文件加載等等。

3. Bean屬性定義新增初始化和銷(xiāo)毀

cn.bugstack.springframework.beans.factory.config.BeanDefinition

  1. public class BeanDefinition { 
  2.  
  3.     private Class beanClass; 
  4.  
  5.     private PropertyValues propertyValues; 
  6.  
  7.     private String initMethodName; 
  8.      
  9.     private String destroyMethodName; 
  10.      
  11.     // ...get/set 
  • 在 BeanDefinition 新增加了兩個(gè)屬性:initMethodName、destroyMethodName,這兩個(gè)屬性是為了在 spring.xml 配置的 Bean 對(duì)象中,可以配置 init-method="initDataMethod" destroy-method="destroyDataMethod" 操作,最終實(shí)現(xiàn)接口的效果是一樣的。只不過(guò)一個(gè)是接口方法的直接調(diào)用,另外是一個(gè)在配置文件中讀取到方法反射調(diào)用

4. 執(zhí)行 Bean 對(duì)象的初始化方法

cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

  1. public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { 
  2.  
  3.     private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy(); 
  4.  
  5.     @Override 
  6.     protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException { 
  7.         Object bean = null
  8.         try { 
  9.             bean = createBeanInstance(beanDefinition, beanName, args); 
  10.             // 給 Bean 填充屬性 
  11.             applyPropertyValues(beanName, bean, beanDefinition); 
  12.             // 執(zhí)行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置處理方法 
  13.             bean = initializeBean(beanName, bean, beanDefinition); 
  14.         } catch (Exception e) { 
  15.             throw new BeansException("Instantiation of bean failed", e); 
  16.         } 
  17.  
  18.         // ... 
  19.  
  20.         addSingleton(beanName, bean); 
  21.         return bean; 
  22.     } 
  23.  
  24.     private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) { 
  25.         // 1. 執(zhí)行 BeanPostProcessor Before 處理 
  26.         Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName); 
  27.  
  28.         // 執(zhí)行 Bean 對(duì)象的初始化方法 
  29.         try { 
  30.             invokeInitMethods(beanName, wrappedBean, beanDefinition); 
  31.         } catch (Exception e) { 
  32.             throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e); 
  33.         } 
  34.  
  35.         // 2. 執(zhí)行 BeanPostProcessor After 處理 
  36.         wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName); 
  37.         return wrappedBean; 
  38.     } 
  39.  
  40.     private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception { 
  41.         // 1. 實(shí)現(xiàn)接口 InitializingBean 
  42.         if (bean instanceof InitializingBean) { 
  43.             ((InitializingBean) bean).afterPropertiesSet(); 
  44.         } 
  45.  
  46.         // 2. 配置信息 init-method {判斷是為了避免二次執(zhí)行銷(xiāo)毀} 
  47.         String initMethodName = beanDefinition.getInitMethodName(); 
  48.         if (StrUtil.isNotEmpty(initMethodName)) { 
  49.             Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName); 
  50.             if (null == initMethod) { 
  51.                 throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'"); 
  52.             } 
  53.             initMethod.invoke(bean); 
  54.         } 
  55.     } 
  56.  
  • 抽象類(lèi) AbstractAutowireCapableBeanFactory 中的 createBean 是用來(lái)創(chuàng)建 Bean 對(duì)象的方法,在這個(gè)方法中我們之前已經(jīng)擴(kuò)展了 BeanFactoryPostProcessor、BeanPostProcessor 操作,這里我們繼續(xù)完善執(zhí)行 Bean 對(duì)象的初始化方法的處理動(dòng)作。
  • 在方法 invokeInitMethods 中,主要分為兩塊來(lái)執(zhí)行實(shí)現(xiàn)了 InitializingBean 接口的操作,處理 afterPropertiesSet 方法。另外一個(gè)是判斷配置信息 init-method 是否存在,執(zhí)行反射調(diào)用 initMethod.invoke(bean)。這兩種方式都可以在 Bean 對(duì)象初始化過(guò)程中進(jìn)行處理加載 Bean 對(duì)象中的初始化操作,讓使用者可以額外新增加自己想要的動(dòng)作。

5. 定義銷(xiāo)毀方法適配器(接口和配置)

cn.bugstack.springframework.beans.factory.support.DisposableBeanAdapter

  1. public class DisposableBeanAdapter implements DisposableBean { 
  2.  
  3.     private final Object bean; 
  4.     private final String beanName; 
  5.     private String destroyMethodName; 
  6.  
  7.     public DisposableBeanAdapter(Object bean, String beanName, BeanDefinition beanDefinition) { 
  8.         this.bean = bean; 
  9.         this.beanName = beanName; 
  10.         this.destroyMethodName = beanDefinition.getDestroyMethodName(); 
  11.     } 
  12.  
  13.     @Override 
  14.     public void destroy() throws Exception { 
  15.         // 1. 實(shí)現(xiàn)接口 DisposableBean 
  16.         if (bean instanceof DisposableBean) { 
  17.             ((DisposableBean) bean).destroy(); 
  18.         } 
  19.  
  20.         // 2. 配置信息 destroy-method {判斷是為了避免二次執(zhí)行銷(xiāo)毀} 
  21.         if (StrUtil.isNotEmpty(destroyMethodName) && !(bean instanceof DisposableBean && "destroy".equals(this.destroyMethodName))) { 
  22.             Method destroyMethod = bean.getClass().getMethod(destroyMethodName); 
  23.             if (null == destroyMethod) { 
  24.                 throw new BeansException("Couldn't find a destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'"); 
  25.             } 
  26.             destroyMethod.invoke(bean); 
  27.         } 
  28.          
  29.     } 
  30.  
  • 可能你會(huì)想這里怎么有一個(gè)適配器的類(lèi)呢,因?yàn)殇N(xiāo)毀方法有兩種甚至多種方式,目前有實(shí)現(xiàn)接口 DisposableBean、配置信息 destroy-method,兩種方式。而這兩種方式的銷(xiāo)毀動(dòng)作是由 AbstractApplicationContext 在注冊(cè)虛擬機(jī)鉤子后看,虛擬機(jī)關(guān)閉前執(zhí)行的操作動(dòng)作。
  • 那么在銷(xiāo)毀執(zhí)行時(shí)不太希望還得關(guān)注都銷(xiāo)毀那些類(lèi)型的方法,它的使用上更希望是有一個(gè)統(tǒng)一的接口進(jìn)行銷(xiāo)毀,所以這里就新增了適配類(lèi),做統(tǒng)一處理。

6. 創(chuàng)建Bean時(shí)注冊(cè)銷(xiāo)毀方法對(duì)象

cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

  1. public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { 
  2.  
  3.     private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy(); 
  4.  
  5.     @Override 
  6.     protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException { 
  7.         Object bean = null
  8.         try { 
  9.             bean = createBeanInstance(beanDefinition, beanName, args); 
  10.             // 給 Bean 填充屬性 
  11.             applyPropertyValues(beanName, bean, beanDefinition); 
  12.             // 執(zhí)行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置處理方法 
  13.             bean = initializeBean(beanName, bean, beanDefinition); 
  14.         } catch (Exception e) { 
  15.             throw new BeansException("Instantiation of bean failed", e); 
  16.         } 
  17.  
  18.         // 注冊(cè)實(shí)現(xiàn)了 DisposableBean 接口的 Bean 對(duì)象 
  19.         registerDisposableBeanIfNecessary(beanName, bean, beanDefinition); 
  20.  
  21.         addSingleton(beanName, bean); 
  22.         return bean; 
  23.     } 
  24.  
  25.     protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) { 
  26.         if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) { 
  27.             registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition)); 
  28.         } 
  29.     } 
  30.  

在創(chuàng)建 Bean 對(duì)象的實(shí)例的時(shí)候,需要把銷(xiāo)毀方法保存起來(lái),方便后續(xù)執(zhí)行銷(xiāo)毀動(dòng)作進(jìn)行調(diào)用。

那么這個(gè)銷(xiāo)毀方法的具體方法信息,會(huì)被注冊(cè)到 DefaultSingletonBeanRegistry 中新增加的 Map

在注冊(cè)銷(xiāo)毀方法的時(shí)候,會(huì)根據(jù)是接口類(lèi)型和配置類(lèi)型統(tǒng)一交給 DisposableBeanAdapter 銷(xiāo)毀適配器類(lèi)來(lái)做統(tǒng)一處理。實(shí)現(xiàn)了某個(gè)接口的類(lèi)可以被 instanceof 判斷或者強(qiáng)轉(zhuǎn)后調(diào)用接口方法

7. 虛擬機(jī)關(guān)閉鉤子注冊(cè)調(diào)用銷(xiāo)毀方法

cn.bugstack.springframework.context.ConfigurableApplicationContext

  1. public interface ConfigurableApplicationContext extends ApplicationContext { 
  2.  
  3.     void refresh() throws BeansException; 
  4.  
  5.     void registerShutdownHook(); 
  6.  
  7.     void close(); 
  8.  
  • 首先我們需要在 ConfigurableApplicationContext 接口中定義注冊(cè)虛擬機(jī)鉤子的方法 registerShutdownHook 和手動(dòng)執(zhí)行關(guān)閉的方法 close。

cn.bugstack.springframework.context.support.AbstractApplicationContext

  1. public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { 
  2.  
  3.     // ... 
  4.  
  5.     @Override 
  6.     public void registerShutdownHook() { 
  7.         Runtime.getRuntime().addShutdownHook(new Thread(this::close)); 
  8.     } 
  9.  
  10.     @Override 
  11.     public void close() { 
  12.         getBeanFactory().destroySingletons(); 
  13.     } 
  14.  
  • 這里主要體現(xiàn)了關(guān)于注冊(cè)鉤子和關(guān)閉的方法實(shí)現(xiàn),上文提到過(guò)的 Runtime.getRuntime().addShutdownHook,可以嘗試驗(yàn)證。在一些中間件和監(jiān)控系統(tǒng)的設(shè)計(jì)中也可以用得到,比如監(jiān)測(cè)服務(wù)器宕機(jī),執(zhí)行備機(jī)啟動(dòng)操作。

五、測(cè)試

1. 事先準(zhǔn)備

cn.bugstack.springframework.test.bean.UserDao

  1. public class UserDao { 
  2.  
  3.     private static Map<String, String> hashMap = new HashMap<>(); 
  4.  
  5.     public void initDataMethod(){ 
  6.         System.out.println("執(zhí)行:init-method"); 
  7.         hashMap.put("10001""小傅哥"); 
  8.         hashMap.put("10002""八杯水"); 
  9.         hashMap.put("10003""阿毛"); 
  10.     } 
  11.  
  12.     public void destroyDataMethod(){ 
  13.         System.out.println("執(zhí)行:destroy-method"); 
  14.         hashMap.clear(); 
  15.     } 
  16.  
  17.     public String queryUserName(String uId) { 
  18.         return hashMap.get(uId); 
  19.     } 
  20.  

cn.bugstack.springframework.test.bean.UserService

  1. public class UserService implements InitializingBean, DisposableBean { 
  2.  
  3.     private String uId; 
  4.     private String company; 
  5.     private String location; 
  6.     private UserDao userDao; 
  7.  
  8.     @Override 
  9.     public void destroy() throws Exception { 
  10.         System.out.println("執(zhí)行:UserService.destroy"); 
  11.     } 
  12.  
  13.     @Override 
  14.     public void afterPropertiesSet() throws Exception { 
  15.         System.out.println("執(zhí)行:UserService.afterPropertiesSet"); 
  16.     } 
  17.  
  18.     // ...get/set 

UserDao,修改了之前使用 static 靜態(tài)塊初始化數(shù)據(jù)的方式,改為提供 initDataMethod 和 destroyDataMethod 兩個(gè)更優(yōu)雅的操作方式進(jìn)行處理。

UserService,以實(shí)現(xiàn)接口 InitializingBean, DisposableBean 的兩個(gè)方法 destroy()、afterPropertiesSet(),處理相應(yīng)的初始化和銷(xiāo)毀方法的動(dòng)作。afterPropertiesSet,方法名字很好,在屬性設(shè)置后執(zhí)行

2. 配置文件

基礎(chǔ)配置,無(wú)BeanFactoryPostProcessor、BeanPostProcessor,實(shí)現(xiàn)類(lèi)

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans> 
  3.  
  4.     <bean id="userDao" class="cn.bugstack.springframework.test.bean.UserDao" init-method="initDataMethod" destroy-method="destroyDataMethod"/> 
  5.  
  6.     <bean id="userService" class="cn.bugstack.springframework.test.bean.UserService"
  7.         <property name="uId" value="10001"/> 
  8.         <property name="company" value="騰訊"/> 
  9.         <property name="location" value="深圳"/> 
  10.         <property name="userDao" ref="userDao"/> 
  11.     </bean> 
  12.  
  13. </beans> 

 

 

  • 配置文件中主要是新增了,init-method="initDataMethod" destroy-method="destroyDataMethod",這樣兩個(gè)配置。從源碼的學(xué)習(xí)中可以知道,這兩個(gè)配置是為了加入到 BeanDefinition 定義類(lèi)之后寫(xiě)入到類(lèi) DefaultListableBeanFactory 中的 beanDefinitionMap 屬性中去。

3. 單元測(cè)試

  1. @Test 
  2. public void test_xml() { 
  3.     // 1.初始化 BeanFactory 
  4.     ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml"); 
  5.     applicationContext.registerShutdownHook();       
  6.  
  7.     // 2. 獲取Bean對(duì)象調(diào)用方法 
  8.     UserService userService = applicationContext.getBean("userService", UserService.class); 
  9.     String result = userService.queryUserInfo(); 
  10.     System.out.println("測(cè)試結(jié)果:" + result); 
  • 測(cè)試方法中新增加了一個(gè),注冊(cè)鉤子的動(dòng)作。applicationContext.registerShutdownHook();

測(cè)試結(jié)果

執(zhí)行:init-method

執(zhí)行:UserService.afterPropertiesSet

測(cè)試結(jié)果:小傅哥,騰訊,深圳

執(zhí)行:UserService.destroy

執(zhí)行:destroy-method

Process finished with exit code 0

  • 從測(cè)試結(jié)果可以看到,我們的新增加的初始和銷(xiāo)毀方法已經(jīng)可以如期輸出結(jié)果了。

六、總結(jié)

  • 本文主要完成了關(guān)于初始和銷(xiāo)毀在使用接口定義 implements InitializingBean, DisposableBean 和在spring.xml中配置 init-method="initDataMethod" destroy-method="destroyDataMethod" 的兩種具體在 AbstractAutowireCapableBeanFactory 完成初始方法和 AbstractApplicationContext 處理銷(xiāo)毀動(dòng)作的具體實(shí)現(xiàn)過(guò)程。
  • 通過(guò)本文的實(shí)現(xiàn)內(nèi)容,可以看到目前這個(gè) Spring 框架對(duì) Bean 的操作越來(lái)越完善了,可擴(kuò)展性也不斷的增強(qiáng)。你既可以在Bean注冊(cè)完成實(shí)例化前進(jìn)行 BeanFactoryPostProcessor 操作,也可以在Bean實(shí)例化過(guò)程中執(zhí)行前置和后置操作,現(xiàn)在又可以執(zhí)行Bean的初始化方法和銷(xiāo)毀方法。所以一個(gè)簡(jiǎn)單的Bean對(duì)象,已經(jīng)被賦予了各種擴(kuò)展能力。
  • 在學(xué)習(xí)和動(dòng)手實(shí)踐 Spring 框架學(xué)習(xí)的過(guò)程中,特別要注意的是它對(duì)接口和抽象類(lèi)的把握和使用,尤其遇到類(lèi)似,A繼承B實(shí)現(xiàn)C時(shí),C的接口方法由A繼承的父類(lèi)B實(shí)現(xiàn),這樣的操作都蠻有意思的。也是可以復(fù)用到通常的業(yè)務(wù)系統(tǒng)開(kāi)發(fā)中進(jìn)行處理一些復(fù)雜邏輯的功能分層,做到程序的可擴(kuò)展、易維護(hù)等特性。

 

責(zé)任編輯:武曉燕 來(lái)源: bugstack蟲(chóng)洞棧
相關(guān)推薦

2009-12-16 14:04:04

Ruby對(duì)象初始化

2018-05-08 14:47:38

虛擬機(jī)方法代碼

2012-02-28 10:04:09

Java

2023-04-08 14:22:16

Spring初始化對(duì)象

2011-06-17 15:29:44

C#對(duì)象初始化器集合初始化器

2023-06-27 08:28:00

2012-05-18 10:22:23

2011-03-17 09:58:43

Java虛擬機(jī)JVM

2020-12-08 05:58:57

CPU虛擬化虛擬機(jī)

2012-05-23 12:46:53

JavaJava類(lèi)

2011-03-16 10:52:20

2010-02-01 14:21:24

C++初始化列表

2009-07-31 17:51:27

C#對(duì)象初始化

2013-07-17 09:32:58

2010-10-13 10:21:37

物理機(jī)虛擬機(jī)遷移

2010-01-22 15:47:37

VB.NET初始化網(wǎng)格

2018-10-11 11:07:28

Windows虛擬機(jī)方法

2010-07-26 09:02:38

2022-01-26 16:30:47

代碼虛擬機(jī)Linux

2018-03-13 15:08:19

虛擬機(jī)CPU虛擬化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)