一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|JavaScript|易語(yǔ)言|

服務(wù)器之家 - 編程語(yǔ)言 - JAVA教程 - Spring生命周期回調(diào)與容器擴(kuò)展詳解

Spring生命周期回調(diào)與容器擴(kuò)展詳解

2021-03-11 14:09liuxigiant JAVA教程

這篇文章主要介紹了Spring生命周期回調(diào)與容器擴(kuò)展詳解,具有一定借鑒價(jià)值,需要的朋友可以參考下。

本篇主要總結(jié)下Spring容器在初始化實(shí)例前后,提供的一些回調(diào)方法和可擴(kuò)展點(diǎn)。利用這些方法和擴(kuò)展點(diǎn),可以實(shí)現(xiàn)在Spring初始化實(shí)例前后做一些特殊邏輯處理。

下面主要介紹:

類級(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è)試類如下:

?
1
2
3
<bean id = "initMethodBeanService" class="name.liuxi.spring.ext.InitMethodBeanService" init-method="init">
   <property name="f2" value="2"/>
</bean>

測(cè)試類如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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é)果打印如下:

?
1
2
3
4
5
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)方法

?
1
2
3
4
@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í)例初始化后處理器示例

?
1
2
3
4
5
6
7
8
9
10
11
12
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配置如下:

?
1
2
3
4
5
6
7
8
9
10
11
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations" value="classpath:com/foo/jdbc.properties"/>
</bean>
 
<bean id="dataSource" destroy-method="close"
    class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="${jdbc.driverClassName}"/>
  <property name="url" value="${jdbc.url}"/>
  <property name="username" value="${jdbc.username}"/>
  <property name="password" value="${jdbc.password}"/>
</bean>

屬性配置文件jdbc.properties如下:

?
1
2
3
4
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è)新的方式,如下:

?
1
<context:property-override location="classpath:override.properties"/>

override.properties屬性配置文件的屬性的命名規(guī)則和上面不同(上面例子中需要保證屬性名和占位符一致),命名規(guī)則是beanName.property

?
1
2
3
4
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

?
1
2
3
4
5
6
7
8
9
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

?
1
2
3
4
<bean class="name.liuxi.spring.ext.BeanFactoryPostProcessorService"/>
<bean id="user" class="name.liuxi.spring.ext.UserBean">
   <property name="userName" value="haha"/>
</bean>

下面是自定義的bean factory后處理器,修改屬性u(píng)serName的值為heihei

?
1
2
3
4
5
6
7
8
9
10
11
12
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");
    }
  }
}

總結(jié)

以上就是本文關(guān)于Spring生命周期回調(diào)與容器擴(kuò)展詳解的全部?jī)?nèi)容,希望對(duì)大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!

原文鏈接:http://blog.csdn.net/liuxigiant/article/details/54296578

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲精品专区 | 国产精品第1页在线播放 | 亚欧洲乱码视频一二三区 | 西西人体大胆啪啪私拍色约约 | 鬼畜重口高h合集长短篇 | 午夜私人影院在线观看 视频 | 手机亚洲第一页 | 国产在线精品成人一区二区三区 | 亚洲成色| 白丝憋尿 | 97国产蝌蚪视频在线观看 | 校园全黄h全肉细节文 | 成年人免费在线看 | 精品久久成人免费第三区 | 国产精品成人免费 | 日韩欧美一区二区三区四区 | 97色蜜桃 | 欧美二区视频 | 亚洲免费视频在线 | 亚洲国产精品久久网午夜 | 我们中文在线观看免费完整版 | 国产亚洲精品美女久久久 | 无人在线高清观看 | 亚欧洲乱码专区视频 | 精品久久久久久久久久久 | 免费看成人毛片日本久久 | gay男男白袜chinese| 天天色综合6| 欧美大b| 192.168.191 | 日本高清在线看免费观看 | 国四虎影永久 | 国产成人精品系列在线观看 | 99九九精品免费视频观看 | 俄罗斯12一15处交 | 成人xxxxxx| h肉动漫在线视频无修无遮挡 | 欧美成人手机 | 大妹子最新视频在线观看 | 国产人成激情视频在线观看 | 日韩拍拍拍 |