精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

龍行有風,向虛擬機注冊鉤子,實現Bean對象的初始化和銷毀方法

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

 [[407482]]

目錄

  • 一、前言
  • 二、目標
  • 三、設計
  • 四、實現
    • 1. 工程結構
    • 2. 定義初始化和銷毀方法的接口
    • 3. Bean屬性定義新增初始化和銷毀
    • 4. 執行 Bean 對象的初始化方法
    • 5. 定義銷毀方法適配器(接口和配置)
    • 6. 創建Bean時注冊銷毀方法對象
    • 7. 虛擬機關閉鉤子注冊調用銷毀方法
  • 五、測試
    • 1. 事先準備
    • 2. 配置文件
    • 3. 單元測試
  • 六、總結
  • 七、系列推薦

一、前言

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

[[407483]]

有人說:人人都是產品經理,那你知道嗎,人人也都可以是碼農程序員!就像:

  • 編程就是;定義屬性、創建方法、調用展示
  • Java 和 PHP 就像男人和女人,前者在乎架構化模塊后,后者在乎那個顏色我喜歡
  • 用心寫,但不要不做格式化
  • 初次和產品對接的三個寶:磚頭、鐵鍬、菜刀,分別保證有用、可用、好用
  • 從一行代碼到一噸代碼,開發越來越難,壁壘也越來越高

其實學會寫代碼并不難,但學會寫好代碼卻很難。從易閱讀上來說你的代碼要有準確的命名和清晰的注釋、從易使用上來說你的代碼要具備設計模式的包裝讓對外的服務調用更簡單、從易擴展上來說你的代碼要做好業務和功能的實現分層。在易閱讀、易使用、易擴展以及更多編碼規范的約束下,還需要在開發完成上線后的交付結果上滿足;高可用、高性能、高并發,與此同時你還會接到現有項目中層出不窮來自產品經理新增的需求。

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

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

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

二、目標

當我們的類創建的 Bean 對象,交給 Spring 容器管理以后,這個類對象就可以被賦予更多的使用能力。就像我們在上一章節已經給類對象添加了修改注冊Bean定義未實例化前的屬性信息修改和實例化過程中的前置和后置處理,這些額外能力的實現,都可以讓我們對現有工程中的類對象做相應的擴展處理。

那么除此之外我們還希望可以在 Bean 初始化過程,執行一些操作。比如幫我們做一些數據的加載執行,鏈接注冊中心暴漏RPC接口以及在Web程序關閉時執行鏈接斷開,內存銷毀等操作。如果說沒有Spring我們也可以通過構造函數、靜態方法以及手動調用的方式實現,但這樣的處理方式終究不如把諸如此類的操作都交給 Spring 容器來管理更加合適。 因此你會看到到 spring.xml 中有如下操作:

需要滿足用戶可以在 xml 中配置初始化和銷毀的方法,也可以通過實現類的方式處理,比如我們在使用 Spring 時用到的 InitializingBean, DisposableBean 兩個接口。-其實還可以有一種是注解的方式處理初始化操作,不過目前還沒有實現到注解的邏輯,后續再完善此類功能。

三、設計

可能面對像 Spring 這樣龐大的框架,對外暴露的接口定義使用或者xml配置,完成的一系列擴展性操作,都讓 Spring 框架看上去很神秘。其實對于這樣在 Bean 容器初始化過程中額外添加的處理操作,無非就是預先執行了一個定義好的接口方法或者是反射調用類中xml中配置的方法,最終你只要按照接口定義實現,就會有 Spring 容器在處理的過程中進行調用而已。整體設計結構如下圖:

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

四、實現

1. 工程結構

  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 

工程源碼:公眾號「bugstack蟲洞棧」,回復:Spring 專欄,獲取完整源碼

Spring 應用上下文和對Bean對象擴展機制的類關系,如圖 8-4

圖 8-4

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

2. 定義初始化和銷毀方法的接口

cn.bugstack.springframework.beans.factory.InitializingBean

  1. public interface InitializingBean { 
  2.  
  3.     /** 
  4.      * Bean 處理了屬性填充后調用 
  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,兩個接口方法還是比較常用的,在一些需要結合 Spring 實現的組件中,經常會使用這兩個方法來做一些參數的初始化和銷毀操作。比如接口暴漏、數據庫數據讀取、配置文件加載等等。

3. Bean屬性定義新增初始化和銷毀

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 新增加了兩個屬性:initMethodName、destroyMethodName,這兩個屬性是為了在 spring.xml 配置的 Bean 對象中,可以配置 init-method="initDataMethod" destroy-method="destroyDataMethod" 操作,最終實現接口的效果是一樣的。只不過一個是接口方法的直接調用,另外是一個在配置文件中讀取到方法反射調用

4. 執行 Bean 對象的初始化方法

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.             // 執行 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. 執行 BeanPostProcessor Before 處理 
  26.         Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName); 
  27.  
  28.         // 執行 Bean 對象的初始化方法 
  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. 執行 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. 實現接口 InitializingBean 
  42.         if (bean instanceof InitializingBean) { 
  43.             ((InitializingBean) bean).afterPropertiesSet(); 
  44.         } 
  45.  
  46.         // 2. 配置信息 init-method {判斷是為了避免二次執行銷毀} 
  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.  
  • 抽象類 AbstractAutowireCapableBeanFactory 中的 createBean 是用來創建 Bean 對象的方法,在這個方法中我們之前已經擴展了 BeanFactoryPostProcessor、BeanPostProcessor 操作,這里我們繼續完善執行 Bean 對象的初始化方法的處理動作。
  • 在方法 invokeInitMethods 中,主要分為兩塊來執行實現了 InitializingBean 接口的操作,處理 afterPropertiesSet 方法。另外一個是判斷配置信息 init-method 是否存在,執行反射調用 initMethod.invoke(bean)。這兩種方式都可以在 Bean 對象初始化過程中進行處理加載 Bean 對象中的初始化操作,讓使用者可以額外新增加自己想要的動作。

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

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. 實現接口 DisposableBean 
  16.         if (bean instanceof DisposableBean) { 
  17.             ((DisposableBean) bean).destroy(); 
  18.         } 
  19.  
  20.         // 2. 配置信息 destroy-method {判斷是為了避免二次執行銷毀} 
  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.  
  • 可能你會想這里怎么有一個適配器的類呢,因為銷毀方法有兩種甚至多種方式,目前有實現接口 DisposableBean、配置信息 destroy-method,兩種方式。而這兩種方式的銷毀動作是由 AbstractApplicationContext 在注冊虛擬機鉤子后看,虛擬機關閉前執行的操作動作。
  • 那么在銷毀執行時不太希望還得關注都銷毀那些類型的方法,它的使用上更希望是有一個統一的接口進行銷毀,所以這里就新增了適配類,做統一處理。

6. 創建Bean時注冊銷毀方法對象

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.             // 執行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置處理方法 
  13.             bean = initializeBean(beanName, bean, beanDefinition); 
  14.         } catch (Exception e) { 
  15.             throw new BeansException("Instantiation of bean failed", e); 
  16.         } 
  17.  
  18.         // 注冊實現了 DisposableBean 接口的 Bean 對象 
  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.  

在創建 Bean 對象的實例的時候,需要把銷毀方法保存起來,方便后續執行銷毀動作進行調用。

那么這個銷毀方法的具體方法信息,會被注冊到 DefaultSingletonBeanRegistry 中新增加的 Map

在注冊銷毀方法的時候,會根據是接口類型和配置類型統一交給 DisposableBeanAdapter 銷毀適配器類來做統一處理。實現了某個接口的類可以被 instanceof 判斷或者強轉后調用接口方法

7. 虛擬機關閉鉤子注冊調用銷毀方法

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 接口中定義注冊虛擬機鉤子的方法 registerShutdownHook 和手動執行關閉的方法 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.  
  • 這里主要體現了關于注冊鉤子和關閉的方法實現,上文提到過的 Runtime.getRuntime().addShutdownHook,可以嘗試驗證。在一些中間件和監控系統的設計中也可以用得到,比如監測服務器宕機,執行備機啟動操作。

五、測試

1. 事先準備

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("執行:init-method"); 
  7.         hashMap.put("10001""小傅哥"); 
  8.         hashMap.put("10002""八杯水"); 
  9.         hashMap.put("10003""阿毛"); 
  10.     } 
  11.  
  12.     public void destroyDataMethod(){ 
  13.         System.out.println("執行: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("執行:UserService.destroy"); 
  11.     } 
  12.  
  13.     @Override 
  14.     public void afterPropertiesSet() throws Exception { 
  15.         System.out.println("執行:UserService.afterPropertiesSet"); 
  16.     } 
  17.  
  18.     // ...get/set 

UserDao,修改了之前使用 static 靜態塊初始化數據的方式,改為提供 initDataMethod 和 destroyDataMethod 兩個更優雅的操作方式進行處理。

UserService,以實現接口 InitializingBean, DisposableBean 的兩個方法 destroy()、afterPropertiesSet(),處理相應的初始化和銷毀方法的動作。afterPropertiesSet,方法名字很好,在屬性設置后執行

2. 配置文件

基礎配置,無BeanFactoryPostProcessor、BeanPostProcessor,實現類

  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",這樣兩個配置。從源碼的學習中可以知道,這兩個配置是為了加入到 BeanDefinition 定義類之后寫入到類 DefaultListableBeanFactory 中的 beanDefinitionMap 屬性中去。

3. 單元測試

  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對象調用方法 
  8.     UserService userService = applicationContext.getBean("userService", UserService.class); 
  9.     String result = userService.queryUserInfo(); 
  10.     System.out.println("測試結果:" + result); 
  • 測試方法中新增加了一個,注冊鉤子的動作。applicationContext.registerShutdownHook();

測試結果

執行:init-method

執行:UserService.afterPropertiesSet

測試結果:小傅哥,騰訊,深圳

執行:UserService.destroy

執行:destroy-method

Process finished with exit code 0

  • 從測試結果可以看到,我們的新增加的初始和銷毀方法已經可以如期輸出結果了。

六、總結

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

 

責任編輯:武曉燕 來源: bugstack蟲洞棧
相關推薦

2009-12-16 14:04:04

Ruby對象初始化

2018-05-08 14:47:38

虛擬機方法代碼

2012-02-28 10:04:09

Java

2023-04-08 14:22:16

Spring初始化對象

2011-06-17 15:29:44

C#對象初始化器集合初始化器

2023-06-27 08:28:00

2020-12-08 05:58:57

CPU虛擬化虛擬機

2012-05-18 10:22:23

2010-02-01 14:21:24

C++初始化列表

2012-05-23 12:46:53

JavaJava類

2011-03-17 09:58:43

Java虛擬機JVM

2011-03-16 10:52:20

2009-07-31 17:51:27

C#對象初始化

2010-07-26 09:02:38

2013-07-17 09:32:58

2018-03-13 15:08:19

虛擬機CPU虛擬化

2010-01-22 15:47:37

VB.NET初始化網格

2010-10-13 10:21:37

物理機虛擬機遷移

2018-10-11 11:07:28

Windows虛擬機方法

2022-01-26 16:30:47

代碼虛擬機Linux
點贊
收藏

51CTO技術棧公眾號

99久久er热在这里只有精品15| 久久不见久久见免费视频7| 亚洲美女屁股眼交3| 亚洲va国产va天堂va久久| 日韩成人毛片视频| 年轻的保姆91精品| 亚洲第一福利视频在线| 精品久久蜜桃| 国产免费av一区| 欧美日中文字幕| 免费成人av| 亚洲国产va精品久久久不卡综合| 国产精品久久久久久久小唯西川| 91午夜视频在线观看| 香蕉久久夜色精品国产使用方法| 一本高清dvd不卡在线观看| 欧美精品123| 91精东传媒理伦片在线观看| 精品91视频| 亚洲网站在线看| 少妇一区二区三区| 国产成人日日夜夜| 午夜免费久久久久| 免费看黄色的视频| 久久9999免费视频| 欧美日韩在线视频观看| 欧美中日韩免费视频| 国产精品久久久久久久久毛片 | 久久综合久久88| 国产资源中文字幕| 亚洲少妇视频| 国产精品久久久久久久久图文区| 91|九色|视频| 无码人妻丰满熟妇精品区| 欧美福利影院| 亚洲欧美精品在线| 天堂在线精品视频| 欧美日韩视频免费观看| 亚洲综合免费观看高清完整版在线| 蜜桃传媒一区二区| 国产成a人亚洲精v品无码| 午夜亚洲性色福利视频| 久久久久国产视频| 日韩在线观看免| 在线一级成人| 精品国产乱码久久久久久久久| 怡红院亚洲色图| 唐人社导航福利精品| 亚洲一区二区综合| 在线观看免费91| 国产黄在线看| 久久综合色之久久综合| 99在线视频播放| 在线观看中文字幕av| 免费在线观看成人av| 色综合天天狠天天透天天伊人 | 日本欧美日韩| 欧美日韩国产在线看| 国产一区二区三区在线免费| 日本中文字幕伦在线观看| 国产性天天综合网| 牛人盗摄一区二区三区视频| 刘亦菲久久免费一区二区| 国产一二精品视频| 成人免费激情视频| 最近中文在线观看| 日日夜夜精品免费视频| 国产91精品久久久久久久| www.99re7.com| 欧美久久成人| 另类色图亚洲色图| 午夜剧场免费在线观看| 99久久99久久精品国产片桃花| 亚洲欧美日韩精品久久亚洲区| www.88av| 精品一区在线| 中文字幕成人在线| 夫妇露脸对白88av| 欧美激情另类| 久久亚洲国产精品| 男女性高潮免费网站| 欧美日韩a区| 久久九九国产精品怡红院| 国产一区第一页| 亚洲欧美综合久久久| 久久久极品av| 九九热只有精品| 欧美在线高清| 欧美激情小视频| 中文字幕亚洲高清| 日韩av成人高清| 国产精品高清在线| 国产精品嫩草影院桃色| 国产精品一区二区久久精品爱涩| 91精品国产99久久久久久红楼| 北条麻妃一二三区| 91小视频在线| 欧美日韩综合精品| 欧美成人三区| 午夜精品福利一区二区三区蜜桃| 黄网站欧美内射| 免费看av不卡| 欧美日韩精品一区二区三区| 欧美黑人又粗又大又爽免费| 成人在线高清| 日韩女优毛片在线| 久久国产精品影院| 999久久久国产精品| 欧美日本亚洲视频| 日本a级c片免费看三区| 久久精品国产精品亚洲综合| 成人av影视在线| 137大胆人体在线观看| 天天av天天翘天天综合网色鬼国产| 无限资源日本好片| 日韩精品社区| 久久久久久久久久久免费精品| 18国产免费视频| 91在线小视频| www.亚洲成人网| 亚洲我射av| 夜夜嗨av色综合久久久综合网 | 国产1区2区3区在线| 午夜精品久久久久影视| 一本之道在线视频| 日韩中文首页| 国产精品久久av| 日本一级在线观看| 性久久久久久久| 在线成人精品视频| 综合亚洲视频| 国产有码在线一区二区视频| 久久久pmvav| 亚洲二区视频在线| 最新国产精品自拍| 欧美va天堂在线| 97超级在线观看免费高清完整版电视剧| 国产在线视频网| 色狠狠色狠狠综合| www.av天天| 美女黄色成人网| 麻豆视频成人| 亚洲欧洲自拍| 亚洲欧美精品在线| 性色av免费观看| 久久婷婷综合激情| 国产日产欧美视频| 校花撩起jk露出白色内裤国产精品| 韩国三级日本三级少妇99| 亚洲精品一级片| 亚洲午夜一区二区| 91精品啪在线观看国产| 最新成人av网站| 国产一区二区久久久| 欧美a级在线观看| 日韩精品黄色网| 男操女视频网站| 欧美激情资源网| av视屏在线播放| 成人影院在线| 91网站在线看| 国产极品人妖在线观看| 亚洲第一在线视频| 久久精品视频7| 欧美国产综合一区二区| 91热这里只有精品| 国产精品久久久久久影院8一贰佰 国产精品久久久久久麻豆一区软件 | 亚洲三级在线看| 久久精品无码专区| 亚洲欧美不卡| 一本一道久久a久久综合精品| 欧美一区二区三区婷婷| 久99久在线视频| 天堂网av2014| 欧洲亚洲精品在线| 日韩激情小视频| www.亚洲在线| 欧美精品aaaa| 欧美福利网址| 欧美精品一区二区三区四区五区| 日韩毛片网站| 97久久久久久| av资源网站在线观看| 日韩一区二区免费电影| 久久久久久少妇| 综合在线观看色| 欧美无人区码suv| 蜜臀精品一区二区三区在线观看| 777久久精品一区二区三区无码| 日韩a级大片| 91精品国产综合久久久久久蜜臀| sis001亚洲原创区| 在线看福利67194| 黄色av一区二区三区| 91黄视频在线观看| 日本免费在线播放| 国产精品人人做人人爽人人添| 久久久久亚洲av无码麻豆| 久久久久久穴| 黄色网在线视频| 日韩理论片av| 精品日产一区2区三区黄免费 | 福利小视频在线| 一区二区av在线| 日韩一区免费视频| 欧美乱妇15p| 波多野结衣电车痴汉| 亚洲午夜在线视频| 久久高清内射无套| 欧美国产日韩在线观看| 国产人成视频在线观看| 加勒比av一区二区| 天天操天天摸天天爽| 亚洲一区视频| 婷婷五月综合缴情在线视频| 亚洲蜜桃视频| 亚洲一区二区三区四区中文| 综合亚洲色图| 国产精品乱码视频| 久久国际精品| 亚洲xxxx3d| 精品三级在线| 国产精品久久久久久久久久99| 日韩伦理福利| 国内揄拍国内精品| 暖暖在线中文免费日本| 精品久久久av| 日本在线免费网| 中文字幕v亚洲ⅴv天堂| 国产视频精选在线| 亚洲人成电影在线播放| 亚洲人视频在线观看| 精品噜噜噜噜久久久久久久久试看 | 1区1区3区4区产品乱码芒果精品| 成人日韩av| 国产成人综合久久| 欧美18—19sex性hd| 日本成人激情视频| 久久电影tv| 国产成人久久精品| 第四色男人最爱上成人网| 青草成人免费视频| 免费福利视频一区二区三区| 欧美专区在线观看| 欧美粗大gay| 国产成人黄色av| 亚洲mmav| 国产噜噜噜噜噜久久久久久久久| 色综合天天色| 国产精品久久久91| 久久久免费人体| 成人h片在线播放免费网站| 91精品福利观看| 91人人爽人人爽人人精88v| 日韩视频一二区| 岛国视频一区| 日韩高清成人在线| 日韩中文一区| 久久资源中文字幕| 午夜久久久久久久久久久| 欧美日韩亚洲一区| 久久久久久人妻一区二区三区| 9国产精品视频| 十八禁视频网站在线观看| 青青草91视频| 男女视频在线观看网站| 国产成+人+日韩+欧美+亚洲| 国产精品一级黄片| 国产农村妇女精品| 侵犯稚嫩小箩莉h文系列小说| 亚洲综合偷拍欧美一区色| 国产无遮挡裸体免费视频| 日本高清不卡在线观看| 91tv国产成人福利| 亚洲精品一区二区三区蜜桃下载 | 97在线视频免费| 国产v综合v| 91文字幕巨乱亚洲香蕉| 在线成人动漫av| mm131午夜| 亚洲一区免费| 午夜激情视频网| 99久久精品国产一区二区三区| 欧美日韩国产黄色| 亚洲永久精品国产| 波多野结衣一二区| 日韩欧美一级二级三级| 你懂的在线观看| 米奇精品一区二区三区在线观看| 天堂√中文最新版在线| 国产日本欧美一区二区三区在线 | 亚洲国产精品视频在线观看 | 国产精品传媒入口麻豆| 国产亚洲精品女人久久久久久| 色婷婷综合视频在线观看| 99视频在线观看免费| 亚洲精品色婷婷福利天堂| 国产午夜精品久久久久免费视| 91精品国产高清久久久久久91| 欧美videos粗暴| 久久久久久九九九九| 重囗味另类老妇506070| 五月婷婷激情久久| 成人的网站免费观看| 亚洲综合图片一区| 色国产综合视频| 日本高清视频免费观看| 中文字幕亚洲欧美| 中文字幕在线官网| 99高清视频有精品视频| 国产精品手机在线播放| 轻点好疼好大好爽视频| 久久国产成人午夜av影院| 中文在线一区二区三区| 一区二区在线免费观看| 亚洲无码精品在线观看| 亚洲欧美综合另类中字| 92久久精品| 国产精品国模大尺度私拍| 国产精品成人一区二区不卡| 中文字幕国产传媒| 久久精品亚洲精品国产欧美| 久久精品国产亚洲av无码娇色| 91精品国产综合久久精品app| 丁香在线视频| 日本aⅴ大伊香蕉精品视频| 麻豆一区二区麻豆免费观看| 国产精品av免费观看| 国产美女娇喘av呻吟久久| 日韩av网站在线播放| 欧美亚洲一区二区三区四区| 天堂av网在线| 欧美亚州一区二区三区| 欧洲vs亚洲vs国产| 国产妇女馒头高清泬20p多| 懂色av一区二区三区蜜臀| 美女福利视频在线观看| 欧美久久久一区| 麻豆视频在线| 91人成网站www| 亚洲国产成人精品女人| 国产三级精品三级在线| 最新日韩av在线| 国产精品无码久久久久成人app| 日韩在线不卡视频| 电影一区二区三区久久免费观看| 99精品视频网站| 国产精品资源网站| 麻豆国产尤物av尤物在线观看| 日韩你懂的电影在线观看| 好久没做在线观看| 国内精品一区二区| 美女久久一区| 国产欧美一区二区三区在线观看视频| 欧美亚洲一区二区在线观看| 欧美激情办公室videoshd| 91在线视频精品| 亚洲婷婷在线| theav精尽人亡av| 色88888久久久久久影院野外| 成年女人的天堂在线| 成人日韩av在线| 影音先锋中文字幕一区二区| 国产福利短视频| 欧美性猛交一区二区三区精品| 精精国产xxxx视频在线| 96久久精品| 欧美专区在线| 熟女av一区二区| 精品国产乱码久久久久久免费 | 91精品人妻一区二区| 在线观看日韩一区| 性欧美video高清bbw| 国内外成人免费视频| 轻轻草成人在线| 久久久久成人片免费观看蜜芽| 亚洲大胆人体视频| 成人不卡视频| 久久亚洲a v| 国产午夜精品一区二区三区嫩草| 国产美女自慰在线观看| 97人人做人人爱| 日韩系列欧美系列| 99热超碰在线| 欧美精品色一区二区三区| 日本在线视频www鲁啊鲁| 欧美色欧美亚洲另类七区| 国产乱子轮精品视频| 中文字幕亚洲精品一区| 久久激情视频久久| 欧美一区二区三区红桃小说| 中日韩av在线播放| 欧美日韩久久久久| av免费网站在线| 日本不卡免费新一二三区| 国产成人无遮挡在线视频| 亚洲精品一区二区二区| 久久人91精品久久久久久不卡| 欧美激情理论| 免费福利视频网站|