小編給大家分享一下Spring生命周期回調(diào)與容器擴(kuò)展的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
成都創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、霞山網(wǎng)絡(luò)推廣、微信小程序定制開(kāi)發(fā)、霞山網(wǎng)絡(luò)營(yíng)銷、霞山企業(yè)策劃、霞山品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們大的嘉獎(jiǎng);成都創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供霞山建站搭建服務(wù),24小時(shí)服務(wù)熱線:18982081108,官方網(wǎng)址:www.cdcxhl.com下面主要介紹:
類級(jí)別的生命周期初始化回調(diào)方法init-method配置、InitializingBean接口和PostConstruct注解
容器級(jí)別的擴(kuò)展BeanPostProcessor接口和BeanFactoryPostProcessor接口
1.類級(jí)別生命周期回調(diào)
1.1init-method
參照:Springbeanxsdinit-method
init-method是在Spring配置文件中聲明bean的時(shí)候的一個(gè)配置項(xiàng)。init-method配置項(xiàng)的值為類中的一個(gè)無(wú)參方法,但可拋出異常。該方法會(huì)在Spring容器實(shí)例化對(duì)象并設(shè)置完屬性值之后被調(diào)用。
init-method能實(shí)現(xiàn)的功能與InitializingBean接口、PostConstruct注解一致
Spring配置文件及測(cè)試類如下:
測(cè)試類如下:
public class InitMethodBeanService { private static Integer f1; private Integer f2; static { f1 = 1; System.out.println("InitMethodBeanService static block execute..."); } public InitMethodBeanService(){ System.out.println("InitMethodBeanService construct method execute..."); } public void init(){ System.out.println("InitMethodBeanService init method execute..."); } public Integer getF2() { return f2; } public void setF2(Integer f2) { this.f2 = f2; System.out.println("InitMethodBeanService setF2 method execute..."); } }
執(zhí)行結(jié)果打印如下:
InitMethodBeanService static block execute... InitMethodBeanService construct method execute... InitMethodBeanService setF2 method execute... InitMethodBeanService init method execute... test method execute...
1.2InitializingBean接口
參照:Spring官方文檔beans-factory-lifecycle-initializingbean
InitializingBean接口中聲明了一個(gè)方法afterPropertiesSet,該方法會(huì)在Spring容器實(shí)例化對(duì)象并設(shè)置完屬性值之后被調(diào)用。和上面的init-method實(shí)現(xiàn)的功能一致,因此Spring不推薦使用InitializingBean接口。
例子比較簡(jiǎn)單,不列出來(lái)了
1.3PostConstruct注解
翻譯:Spring官方文檔beans-postconstruct-and-predestroy-annotations
@PostConstruct注解是和init-method、InitializingBean接口實(shí)現(xiàn)效果一致的生命周期回調(diào)方法
@PostConstruct public void postConstruct(){ System.out.println("PostConstructService postConstruct method execute..."); }
總結(jié)下上面三個(gè)生命周期回調(diào)方法init-method、InitializingBean接口、@PostConstruct注解
1.都是針對(duì)單個(gè)類的實(shí)例化后處理
2.執(zhí)行時(shí)間都是在類實(shí)例化完成,且成員變量完成注入之后調(diào)用的
3.對(duì)于init-method,還可以在Spring配置文件的beans元素下配置默認(rèn)初始化方法,配置項(xiàng)為default-init-method
4.若以上三種方式配置的初始化方法都不一樣,則執(zhí)行順序?yàn)椋篅PostConstruct注解方法–>InitializingBean的afterPropertiesSet–>init-method方法;若三種方式配置的方法一樣,則方法只執(zhí)行一次(參照:Spring官方文檔beans-factory-lifecycle-combined-effect)
5.有初始化回調(diào)方法,對(duì)應(yīng)的也有銷毀的回調(diào)方法。@PostConstruct注解方法–>InitializingBean的afterPropertiesSet–>init-method方法分別對(duì)應(yīng)@PreDestroy注解方法–>DisposableBean的destroy–>destroy-method方法
2.容器級(jí)別擴(kuò)展
翻譯:Spring官方文檔3.8ContainerExtensionPoints
通常情況下,開(kāi)發(fā)人員無(wú)需自定義實(shí)現(xiàn)一個(gè)ApplicationContext的子類去擴(kuò)展SpringIOC容器,SpringIOC容器通過(guò)對(duì)外暴露的一些接口,可實(shí)現(xiàn)對(duì)SpringIOC容器的擴(kuò)展。
2.1BeanPostProcessor接口
2.1.1bean實(shí)例初始化后處理器及后處理器鏈
BeanPostProcessor接口定義了兩個(gè)容器級(jí)別的回調(diào)方法postProcessBeforeInitialization和postProcessAfterInitialization,用于在初始化實(shí)例后的一些邏輯處理,會(huì)針對(duì)容器中的所有實(shí)例進(jìn)行處理。實(shí)現(xiàn)了BeanPostProcessor接口的類,稱之為bean實(shí)例初始化后處理器。
若在SpringIOC容器中集成了多個(gè)實(shí)例初始化后處理器,這些后處理器構(gòu)成的集合稱之為bean實(shí)例初始化后處理器鏈。
postProcessBeforeInitialization方法在類實(shí)例化且成員變量注入完成之后執(zhí)行,初始化方法(例如InitializingBean的afterPropertiesSet方法)之前執(zhí)行
postProcessAfterInitialization方法在類實(shí)例化且成員變量注入完成之后執(zhí)行,初始化方法(例如InitializingBean的afterPropertiesSet方法)之后執(zhí)行
總結(jié):
1.實(shí)例初始化后處理器多用于對(duì)實(shí)例的一些代理操作。Spring中一些使用到AOP的特性也是通過(guò)后處理器的方式實(shí)現(xiàn)的。
2.實(shí)例初始化后處理器鏈?zhǔn)嵌鄠€(gè)后處理器,就會(huì)有執(zhí)行順序的問(wèn)題,可以通過(guò)實(shí)現(xiàn)Ordered接口,指定后處理的執(zhí)行順序,Ordered接口聲明了getOrder方法,方法返回值越小,后處理的優(yōu)先級(jí)越高,越早執(zhí)行。
3.在通過(guò)實(shí)現(xiàn)BeanPostProcessor接口自定義實(shí)例初始化后處理器的時(shí)候,建議也實(shí)現(xiàn)Ordered接口,指定優(yōu)先級(jí)。
4.這些后處理器的作用域是當(dāng)前的SpringIOC容器,即后處理器被聲明的SpringIOC容器。對(duì)于有層次結(jié)構(gòu)的SpringIOC容器,實(shí)例初始化后處理器鏈不會(huì)作用于其他容器所初始化的實(shí)例上,即使兩個(gè)容器在同一層次結(jié)構(gòu)上。
5.實(shí)例初始化后處理器的實(shí)現(xiàn)類只需要和普通的被Spring管理的bean一樣聲明,SpringIOC容器就會(huì)自動(dòng)檢測(cè)到,并添加到實(shí)例初始化后處理器鏈中。
6.相對(duì)于自動(dòng)檢測(cè),我們也可以調(diào)用ConfigurableBeanFactory的addBeanPostProcessor方法,以編程的方式將一個(gè)實(shí)例初始化后處理器添加到實(shí)例初始化后處理器鏈中。這在需要判定添加條件的場(chǎng)景下比較實(shí)用。這種編程式的方式會(huì)忽略到實(shí)現(xiàn)的Ordered接口所指定的順序,而會(huì)作用于所有的被自動(dòng)檢測(cè)的實(shí)例初始化后處理器之前。
2.1.2bean實(shí)例初始化后處理器與AOP
BeanPostProcessor是一個(gè)特殊的接口,實(shí)現(xiàn)這個(gè)接口的類會(huì)被作為Spring管理的bean的實(shí)例的后處理器。因此,在Spring應(yīng)用上下文啟動(dòng)的一個(gè)特殊階段,會(huì)直接初始化所有實(shí)現(xiàn)了BeanPostProcessor接口的實(shí)例,以及該實(shí)例所引用的類也會(huì)被實(shí)例化。然后作為后處理器應(yīng)用于其他普通實(shí)例。
由于AOP的自動(dòng)代理是以實(shí)例化后處理器的方式實(shí)現(xiàn)的,所以無(wú)論是bean實(shí)例初始化后處理器鏈實(shí)例還是其引用的實(shí)例,都不能被自動(dòng)代理。因而,不要在這些實(shí)例上進(jìn)行切面織入。(對(duì)于這些實(shí)例,會(huì)產(chǎn)生這樣的日志消息:“類foo不能被所有的實(shí)例化后處理器鏈處理,即不能被自動(dòng)代理”)。
注意:當(dāng)實(shí)例化后處理器以autowiring或@Resource的方式引用其他bean,Spring容器在以類型匹配依賴注入的時(shí)候,可能會(huì)注入非指定的bean(例如:實(shí)例化后處理器實(shí)現(xiàn)類以Resource方式依賴bean,若set方法和被依賴的bean的名稱一致或者被依賴bean未聲明名稱,則依賴注入會(huì)以類型匹配的方式注入,此時(shí)可能會(huì)注入非指定的bean)。這也會(huì)導(dǎo)致自動(dòng)代理或其他方式的實(shí)例化后處理器處理失敗。
2.1.3bean實(shí)例初始化后處理器示例
public class BeanPostProcessorService implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object o, String s) throws BeansException { System.out.println("BeanPostProcessorService postProcessAfterInitialization method execute... "); return o; } @Override public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { System.out.println("BeanPostProcessorService postProcessBeforeInitialization method execute... "); return o; } }
2.2BeanFactoryPostProcessor接口
2.2.1beanfactory后處理器
通過(guò)實(shí)現(xiàn)BeanFactoryPostProcessor接口,可以讀取容器所管理的bean的配置元數(shù)據(jù),在bean完成實(shí)例化之前進(jìn)行更改,這些bean稱之為beanfactory后處理器。
BeanFactoryPostProcessors與BeanPostProcessor接口的異同點(diǎn):
相同點(diǎn):
都是容器級(jí)別的后處理器
都可配置多個(gè)后處理器,并通過(guò)實(shí)現(xiàn)Ordered接口,指定執(zhí)行順序
都是針對(duì)接口聲明的容器中所管理的bean進(jìn)行處理,在有層級(jí)結(jié)構(gòu)的容器中,不能處理其他容器中的bean,即使兩個(gè)容器是同一層次
都是只需要在容器中和普通bean一樣聲明,容器會(huì)自動(dòng)檢測(cè)到,并注冊(cè)為后處理器
會(huì)忽略延遲初始化屬性配置
不同點(diǎn):
BeanFactoryPostProcessors接口在bean**實(shí)例化前處理bean的配置元數(shù)據(jù),BeanPostProcessor接口在bean實(shí)例化后處理bean的實(shí)例**
BeanFactoryPostProcessors接口也能通過(guò)BeanFactory.getBean()方法獲取bean的實(shí)例,這樣會(huì)引起bean的實(shí)例化。由于BeanFactoryPostProcessors后處理器是在所有bean實(shí)例化之前執(zhí)行,通過(guò)BeanFactory.getBean()方法會(huì)導(dǎo)致提前實(shí)例化bean,從而打破容器標(biāo)準(zhǔn)的生命周期,這樣可能會(huì)引起一些負(fù)面的影響(例如:提前實(shí)例化的bean會(huì)忽略bean實(shí)例化后處理器的處理)。
2.2.2Spring內(nèi)置及自定義beanfactory后處理器
Spring內(nèi)置了一些beanfactory后處理器(例如:PropertyPlaceholderConfigurer和PropertyOverrideConfigurer)。同時(shí)也支持實(shí)現(xiàn)BeanFactoryPostProcessor接口,自定義beanfactory后處理器。下面說(shuō)說(shuō)Spring內(nèi)置的兩個(gè)后處理器和自定義后處理器。
PropertyPlaceholderConfigurer
Spring為了避免主要的XML定義文件的修改而引起的風(fēng)險(xiǎn),提供了配置分離,可以將一些可能變更的變量配置到屬性配置文件中,并在XML定義文件中以占位符的方式引用。這樣,修改配置只需要修改屬性配置文件即可。PropertyPlaceholderConfigurer用于檢測(cè)占位符,并替換占位符為配置屬性值。示例如下:
PropertyPlaceholderConfigurer通過(guò)jdbc.properties屬性配置文件,在運(yùn)行時(shí),將dataSource這個(gè)bean中數(shù)據(jù)庫(kù)相關(guān)信息的屬性占位符替換成對(duì)應(yīng)的配置值。
XML配置如下:
屬性配置文件jdbc.properties如下:
jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
PropertyPlaceholderConfigurer不僅支持屬性配置文件的讀取,也支持讀取系統(tǒng)屬性。通過(guò)systemPropertiesMode屬性值可配置讀取優(yōu)先級(jí)。各種取值說(shuō)明如下:
0:不讀取系統(tǒng)屬性
1:若引用的屬性配置文件中未檢索到對(duì)應(yīng)占位符的配置,則讀取系統(tǒng)屬性。默認(rèn)為1
2:先讀取系統(tǒng)屬性,再讀取引用的屬性配置文件。這種配置可能導(dǎo)致系統(tǒng)屬性覆蓋配置文件。
PropertyOverrideConfigurer
PropertyOverrideConfigurer類可以通過(guò)引用屬性配置文件,直接給容器中的bean賦值。當(dāng)一個(gè)bean的屬性被多個(gè)PropertyOverrideConfigurer類實(shí)例賦值時(shí),最后一個(gè)的值會(huì)覆蓋前面的。
還是以上面給上面的dataSource的bean賦值為例:
PropertyOverrideConfigurer類對(duì)屬性配置文件的引用使用一個(gè)新的方式,如下:
override.properties屬性配置文件的屬性的命名規(guī)則和上面不同(上面例子中需要保證屬性名和占位符一致),命名規(guī)則是beanName.property
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb dataSource.username=sa dataSource.password=root
支持復(fù)合屬性的賦值,但是要保證引用被賦值屬性的對(duì)象非空
例如:foo.fred.bob.sammy=123
自定義bean factory后處理器
自定義bean factory后處理器就是實(shí)現(xiàn)BeanFactoryPostProcessor接口,完成對(duì)Spring容器管理的bean的配置元數(shù)據(jù)進(jìn)行修改。例如:修改類屬性注入的值,示例如下:
定義一個(gè)用戶類UserBean
public class UserBean { private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
Spring XML配置文件配置用戶類,并給用戶名屬性u(píng)serName注入值haha
下面是自定義的bean factory后處理器,修改屬性u(píng)serName的值為heihei
public class BeanFactoryPostProcessorService implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("BeanFactoryPostProcessorService postProcessBeanFactory method execut..."); BeanDefinition bd = beanFactory.getBeanDefinition("user"); MutablePropertyValues pv = bd.getPropertyValues(); if(pv.contains("userName")) { pv.addPropertyValue("userName", "heihei"); } } }
以上是“Spring生命周期回調(diào)與容器擴(kuò)展的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!