<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 495,  comments - 11,  trackbacks - 0

    6.1 兩種后處理器

    Spring 框架提供了很好的擴展性,除了可以與各種第三方框架良好整合外,其IoC容器也允許開發者進行擴展。這種擴展并不是通過實現BeanFactory或ApplicationContext的子類,而是通過兩個后處理器對IoC容器進行擴展。Spring提供了兩種常用的后處理器:

    ?? ● Bean后處理器,這種后處理器會對容器中特定的Bean進行定制,例如功能的??? 加強。

    ?? ● 容器后處理器,這種后處理器對IoC容器進行特定的后處理。

    下面將介紹這兩種常用的后處理器以及兩種后處理器相關知識。

    6.1.1 Bean后處理器

    Bean后處理器是一種特殊的Bean,這種特殊的Bean并不對外提供服務,它無須id屬性,但它負責對容器中的其他Bean執行后處理,例如為容器中的目標Bean生成代理。這種Bean可稱為Bean后處理器,它在Bean實例創建成功后,對其進行進一步的加強???? 處理。

    Bean后處理器必須實現BeanPostProcessor接口。

    BeanPostProcessor接口包含兩個方法:

    ?? ● Object postProcessBeforeInitialization(Object bean, String name)throws BeansExce- ption,該方法的第一個參數是系統即將初始化的Bean實例,第二個參數是Bean實例的名字。

    ?? ● Object postProcessAfterInitialization(Object bean, String name)throws BeansExce- ption,該方法的第一個參數是系統剛完成初始化的Bean實例,第二個參數是Bean實例的名字。

    實現該接口的Bean必須實現這兩個方法,這兩個方法會對容器的Bean進行后處理。兩個方法會在目標Bean初始化之前和初始化之后分別調用。這兩個方法用于對系統完成的默認初始化進行加強。

    注意:Bean后處理器是對IoC容器一種極好的擴展,Bean后處理器可以對容器中的Bean進行后處理,這種后處理完全由開發者決定。

    下面將定義一個簡單的Bean后處理器,該Bean后處理器將對容器中其他Bean進行后處理。Bean后處理器的代碼如下:

    //自定義Bean后處理器,負責后處理容器中所有的Bean

    public class MyBeanPostProcessor implements BeanPostProcessor

    {

    ??? //在初始化bean之前,調用該方法

    ??? public Object postProcessBeforeInitialization(Object bean , String
    ??? beanName)throws BeansException

    ??? {

    ??????? //僅僅打印一行字符串

    ??????? System.out.println("系統正在準備對" + beanName + "進行初始化...");

    ??????? return bean;

    ??? }

    ??? //在初始化bean之后,調用該方法

    ??? public Object postProcessAfterInitialization(Object bean , String
    ??? beanName)throws BeansException

    ??? {

    ??????? System.out.println("系統已經完成對" + beanName + "的初始化");

    ??????? //如果系統剛完成初始化的bean是Chinese

    ??????? if (bean instanceof Chinese)

    ??????? {

    ??????????? //為Chinese實例設置name屬性

    ??????????? Chinese c = (Chinese)bean;

    ??????????? c.setName("wawa");

    ????? ?? }

    ??????? return bean;

    ??? }

    }

    下面是Chinese的源代碼,該類實現了InitializingBean接口,還額外提供了一個初始化方法,這兩個方法都由Spring容器控制回調。

    public class Chinese implements Person,InitializingBean

    {

    ??? private Axe axe;

    ??? private String name;

    ??? public Chinese()

    ??? {

    ??????? System.out.println("Spring實例化主調bean:Chinese實例...");

    ??? }

    ??? public void setAxe(Axe axe)

    ??? {

    ??????? System.out.println("Spring執行依賴關系注入...");

    ??????? this.axe = axe;

    ??? }

    ??? public void setName(String name)

    ??? {

    ??????? this.name = name;

    ??? }

    ??? public void useAxe()

    ??? {

    ??????? System.out.println(name + axe.chop());

    ??? }

    ??? public void init()

    ??? {

    ??????? System.out.println("正在執行初始化方法?? init...");

    ??? }

    ?? public void afterPropertiesSet() throws Exception

    ??? {

    ?????? System.out.println("正在執行初始化方法 afterPropertiesSet...");

    ??? }

    }

    配置文件如下:

    <?xml version="1.0" encoding="gb2312"?>

    <!-- 指定Spring 配置文件的dtd>

    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

    ??? "http://www.springframework.org/dtd/spring-beans.dtd">

    <!-- Spring配置文件的根元素 -->

    <beans>

    ??? <!-- 配置bean后處理器,可以沒有id屬性,此處id屬性為了后面引用 -->

    ??? <bean id="beanPostProcessor" class="lee.MyBeanPostProcessor"/>

    ??? <bean id="steelAxe" class="lee.SteelAxe"/>

    ??? <bean id="chinese" class="lee.Chinese" init-method="init">

    ??????? <property name="axe" ref="steelAxe"/>

    ??? </bean>

    </beans>

    本應用的chinese具有兩個初始化方法:

    ?? ● init-method指定初始化方法。

    ?? ● 實現InitializingBean接口,提供了afterPropertiesSet初始化方法。

    MyBeanPostProcessor類實現了BeanPostProcessor接口,并實現了該接口的兩個方法,這兩個方法分別在初始化方法調用之前和之后得到回調。

    注意:上面的配置文件配置Bean后處理器時,依然為Bean處理器指定了id屬性,指定id屬性是為了方便程序通過該id屬性訪問Bean后處理器。大部分時候,程序無須手動訪問該Bean后處理器,因此無須為其指定id屬性。

    主程序如下:

    public class BeanTest

    {

    ??? public static void main(String[] args)throws Exception

    ??? {

    ??????? //CLASSPATH路徑下的bean.xml文件創建Resource對象

    ??????? ClassPathResource isr = new ClassPathResource("bean.xml");

    ??????? //以Resource對象作為參數,創建BeanFactory的實例

    ??????? XmlBeanFactory factory = new XmlBeanFactory(isr);

    ??????? //獲取Bean后處理器實例

    ??????? MyBeanPostProcessor beanProcessor =

    ??????????? (MyBeanPostProcessor)factory.getBean("beanPostProcessor");

    ??????? //注冊BeanPostProcessor實例

    ??????? factory.addBeanPostProcessor(beanProcessor);

    ??????? System.out.println("程序已經實例化BeanFactory...");

    ??????? Person p = (Person)factory.getBean("chinese");

    ??????? System.out.println("程序中已經完成了chinese bean的實例化...");

    ??????? p.useAxe();

    ??? }

    }

    如果使用BeanFactory作為Spring容器,必須手動注冊Bean后處理器,因此在程序中先獲取Bean后處理器實例,然后手動注冊——這就是在配置文件中指定Bean后處理器id屬性的原因。通過BeanFactory的addBeanPostProcessor可以注冊BeanPostProcessor實例。程序執行結果如下:

    [java] 程序已經實例化BeanFactory...

    [java] Spring實例化主調bean:Chinese實例...

    [java] Spring實例化依賴bean:SteelAxe實例...

    [java] 系統正在準備對steelAxe進行初始化...

    [java] 系統已經完成對steelAxe的初始化

    [java] Spring執行依賴關系注入...

    [java] 系統正在準備對chinese進行初始化...

    [java] 正在執行初始化方法 afterPropertiesSet...

    [java] 正在執行初始化方法?? init...

    [java] 系統已經完成對chinese的初始化

    [java] 程序中已經完成了chinese bean的實例化...

    [java] wawa鋼斧砍柴真快

    在配置文件中配置chinese實例時,并未指定name屬性值。但程序執行時,name屬性有了值,這就是Bean后處理器完成的,在Bean后處理器中判斷Bean是否是Chinese實例,然后設置它的name屬性。

    容器中一旦注冊了Bean后處理器,Bean后處理器會自動啟動,在容器中每個Bean創建時自動工作,完成加入Bean后處理器需要完成的工作。

    實現BeanPostProcessor接口的Bean后處理器可對Bean進行任何操作,包括完全忽略這個回調。BeanPostProcessor通常用來檢查標記接口或將Bean包裝成一個Proxy的事情。Spring的很多工具類,就是通過Bean后處理器完成的。

    從主程序中看到,采用BeanFactory作為Spring容器時,必須手動注冊BeanPost- Processor。而對于ApplicationContext,則無須手動注冊。ApplicationContext可自動檢測到容器中的Bean后處理器,自動注冊。Bean后處理器會在Bean實例創建時,自動啟動。即主程序采用如下代碼,效果完全一樣:

    public class BeanTest

    {

    ??? public static void main(String[] args)throws Exception

    ??? {

    ??????? ApplicationContext ctx = new ClassPathXmlApplicationContext
    ??????? ("bean.xml");

    ??????? Person p = (Person)factory.getBean("chinese");

    ??????? System.out.println("程序中已經完成了chinese bean的實例化...");

    ??????? p.useAxe();

    ??? }

    }

    使用ApplicationContext作為容器,無須手動注冊BeanPostProcessor。因此,如果需要使用Bean后處理器,Spring容器建議使用ApplicationContext,而不是BeanFactory。

    6.1.2 Bean后處理器的用處

    上一節介紹了一個簡單的Bean后處理器,上面的Bean后處理器負責對容器中的Chinese Bean進行后處理,不管Chinese Bean如何初始化,總是將Chinese Bean的name屬性設置為wawa。這種后處理看起來作用并不是特別大。

    實際上,Bean后處理器完成的工作更加實際,例如生成Proxy。Spring框架本身提供了大量的Bean后處理器,這些后處理器負責對容器中的Bean進行后處理。

    下面是Spring提供的兩個常用的后處理器:

    ?? ● BeanNameAutoProxyCreator,根據Bean實例的name屬性,創建Bean實例的代理。

    ?? ● DefaultAdvisorAutoProxyCreator,根據提供的Advisor,對容器中所有的Bean實例創建代理。

    上面提供的兩個Bean后處理器,都用于根據容器中配置的攔截器創建目標Bean代理,目標代理就在目標Bean的基礎上修改得到。

    注意:如果需要對容器中某一批Bean進行特定的處理,可以考慮使用Bean后處理器。

    6.1.3 容器后處理器

    除了上面提供的Bean后處理器外,Spring還提供了一種容器后處理器。Bean后處理器負責后處理容器生成的所有Bean,而容器后處理器則負責后處理容器本身。

    容器后處理器必須實現BeanFactoryPostProcessor接口。實現該接口必須實現如下一個方法:

    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)

    實現該方法的方法體就是對Spring容器進行的處理,這種處理可以對Spring容器進行任意的擴展,當然也可以對Spring容器不進行任何處理。

    類似于BeanPostProcessor,ApplicationContext可自動檢測到容器中的容器后處理器,并且自動注冊容器后處理器。但若使用BeanFactory作為Spring容器,則必須手動注冊后處理器。

    下面定義了一個容器后處理器,這個容器后處理器實現BeanFactoryPostProcessor接口,但并未對Spring容器進行任何處理,只是打印出一行簡單的信息。該容器后處理器的代碼如下:

    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor

    {

    ??? //容器后處理器對容器進行的處理在該方法中實現

    ??? public void postProcessBeanFactory(ConfigurableListableBeanFactory
    ??? beanFactory)

    ??????? throws BeansException

    ??? {

    ??????? System.out.println("程序對Spring所做的BeanFactory的初始化沒有意
    ??????? 見...");

    ??? }

    }

    將該Bean作為普通Bean部署在容器中,然后使用ApplicationContext作為容器,容器會自動調用BeanFactoryPostProcessor處理Spring容器。程序執行效果如下:

    [java] 程序對Spring所做的BeanFactory的初始化沒有意見...

    實現BeanFactoryPostProcessor接口的Bean后處理器不僅可對BeanFactory執行后處理,也可以對ApplicationContext容器執行后處理。容器后處理器還可用來注冊額外的屬性編輯器。

    注意:Spring沒有提供ApplicationContextPostProcessor。也就是說,對于Application- Context容器,一樣使用BeanFactoryPostProcessor作為容器后處理器。

    Spring已提供如下兩個常用的容器后處理器,包括:

    ?? ● PropertyResourceConfigurer,屬性占位符配置器。

    ?? ● PropertyPlaceHolderConfigurer,另一種屬性占位符配置器。

    下面將詳細介紹這兩種常用的容器后處理器。

    6.1.4 屬性占位符配置器

    Spring提供了PropertyPlaceholderConfigurer,它是一個容器后處理器,負責讀取Java屬性文件里的屬性值,并將這些屬性值設置到Spring容器定義中。

    通過使用PropertyPlaceholderConfigurer后處理器,可以將Spring配置文件中的部分設置放在屬性文件中設置。這種配置方式當然有其優勢:可以將部分相似的配置(如數據庫的urls、用戶名和密碼)放在特定的屬性文件中,如果只需要修改這部分配置,則無須修改Spring配置文件,修改屬性文件即可。

    下面的配置文件配置了PropertyPlaceholderConfigurer后處理器,在配置數據源Bean時,使用了屬性文件中的屬性值。配置文件的代碼如下:

    <?xml version="1.0" encoding="GBK"?>

    <!-- beans是Spring配置文件的根元素,并且指定了Schema信息 -->

    <beans xmlns="http://www.springframework.org/schema/beans"

    ?????? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    ?????? xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    ??? <!-- 配置一個容器后處理器Bean -->

    ??? <bean id="propertyConfigurer"

    ??????? class="org.springframework.beans.factory.config.
    ??????? PropertyPlaceholderConfigurer">

    ??????? <!-- locations屬性指定屬性文件的位置 -->

    ??????? <property name="locations">

    ??????????? <list>

    ??????????????? <value>dbconn.properties</value>

    ??????????????? <!-- 如果有多個屬性文件,依次在下面列出來 -->

    ??????????? </list>

    ??????? </property>

    ??? </bean>

    ??? <!-- 定義數據源Bean,使用C3P0數據源實現 -->

    ??? <bean id="dataSource" class="com.mchange.v2.c3p0.
    ??? ComboPooledDataSource" destroy-method="close">

    ??????? <!-- 指定連接數據庫的驅動 -->

    ??????? <property name="driverClass" value="${jdbc.driverClassName}"/>

    ??????? <!-- 指定連接數據庫的URL -->

    ??????? <property name="jdbcUrl" value="${jdbc.url}"/>

    ??????? <!-- 指定連接數據庫的用戶名 -->

    ??????? <property name="user" value="${jdbc.username}"/>

    ??????? <!-- 指定連接數據庫的密碼 -->

    ??????? <property name="password" value="${jdbc.password}"/>

    ??? </bean>

    </beans>

    在上面的配置文件中,配置driverClass和jdbcUrl等信息時,并未直接設置這些屬性的屬性值,而是設置了${jdbc.driverClassName}和${jdbc.url}屬性值。這表明Spring容器將從propertyConfigurer指定屬性文件中搜索這些key對應的value,并為該Bean的屬性值設置這些value值。

    如前所述,ApplicationContext會自動檢測部署在容器的容器后處理器,無須額外的注冊,容器自動注冊。因此,只需提供如下Java Properties文件:

    jdbc.driverClassName=com.mysql.jdbc.Driver

    jdbc.url=jdbc:mysql://localhost:3306/j2ee

    jdbc.username=root

    jdbc.password=32147

    通過這種方法,可從主XML配置文件中分離出部分配置信息。如果僅需要修改數據庫連接屬性,則無須修改主XML配置文件,只需要修改屬性文件即可。采用屬性占位符的配置方式,可以支持使用多個屬性文件。通過這種方式,可將配置文件分割成多個屬性文件,從而降低修改配置的風險。

    注意:對于數據庫連接等信息集中的配置,可以將其配置在Java屬性文件中,但不要過多地將Spring配置信息抽離到Java屬性文件中,否則可能會降低Spring配置文件的可讀性。

    6.1.5 另一種屬性占位符配置器(PropertyOverrideConfigurer)

    PropertyOverrideConfigurer是Spring提供的另一個容器后處理器,這個后處理器的額作用與上面介紹的容器后處理器作用大致相同。但也存在些許差別:PropertyOverride- Configurer使用的屬性文件用于覆蓋XML配置文件中的定義。即PropertyOverride- Configurer允許XML配置文件中有默認的配置信息。

    如果PropertyOverrideConfigurer的屬性文件有對應配置信息,XML文件中的配置信息被覆蓋;否則,直接使用XML文件中的配置信息。使用PropertyOverrideConfigurer的屬性文件,應是如下的格式:

    beanName.property=value

    beanName是屬性占位符試圖覆蓋的Bean名,property是試圖覆蓋的屬性名。看如下配置文件:

    <?xml version="1.0" encoding="GBK"?>

    <!-- beans是Spring配置文件的根元素,并且指定了Schema信息 -->

    <beans xmlns="http://www.springframework.org/schema/beans"

    ?????? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    ?????? xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    ??? <!-- 配置一個屬性占位符Bean。ApplictionContext能自動識別
    ??? PropertyPlaceholderConfigurer Bean -->

    ??? <bean id="propertyOverrider"

    ??????? class="org.springframework.beans.factory.config.
    ??????? PropertyOverrideConfigurer">

    ??????? <property name="locations">

    ??????????? <list>

    ??? ??????????? <value>dbconn.properties</value>

    ??????????????? <!-- 如果有多個屬性文件,依次在下面列出來 -->

    ??????????? </list>

    ??????? </property>

    ??? </bean>

    ??? <!-- 定義數據源Bean,使用C3P0數據源實現 -->

    ??? <bean id="dataSource" class="com.mchange.v2.c3p0.
    ??? ComboPooledDataSource" destroy-method="close">

    ??????? <!-- 指定連接數據庫的驅動 -->

    ??????? <property name="driverClass" value="dd"/>

    ??????? <!-- 指定連接數據庫的URL -->

    ??????? <property name="jdbcUrl" value="xx"/>

    ??????? <!-- 指定連接數據庫的用戶名 -->

    ??????? <property name="user" value="dd"/>

    ??????? <!-- 指定連接數據庫的密碼 -->

    ??????? <property name="password" value="xx"/>

    ??? </bean>

    </beans>

    上面的配置文件中,指定數據源Bean的各種屬性值時,只是隨意指定了幾個屬性值,很明顯通過這幾個屬性值無法連接到數據庫服務。

    但因為Spring容器中部署了一個PropertyOverrideConfigurer的容器后處理器,而且Spring容器使用ApplicationContext作為容器,它會自動檢測容器中的容器后處理器,無須額外的注冊,容器自動注冊該后處理器。

    PropertyOverrideConfigurer后處理器讀取dbconn.properties文件中的屬性,用于覆蓋目標Bean的屬性。因此,如果屬性文件中有dataSource Bean屬性的設置,則配置文件中指定的屬性值將沒有任何作用。

    dbconn.properties屬性文件如下:

    dataSource.driverClassName=com.mysql.jdbc.Driver

    dataSource.url=jdbc:mysql://wonder:3306/j2ee

    dataSource.username=root

    dataSource.password=32147

    注意屬性文件的格式必須是:

    beanName.property=value

    也就是說,dataSource必須是容器中真實存在的bean名,否則程序將出錯。

    注意:程序無法知道BeanFactory定義是否被覆蓋。僅僅通過察看XML配置文件,無法知道配置文件的配置信息是否被覆蓋。如有多個PorpertyOverrideConfigurer對同一Bean屬性定義了覆蓋,最后一個覆蓋獲勝。

    posted on 2009-07-19 10:12 jadmin 閱讀(119) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲午夜无码久久久久| 久久久久亚洲Av片无码v| 一级做a爰全过程免费视频毛片| 国产成人精品曰本亚洲79ren| 久久国产免费一区| 亚洲色大18成人网站WWW在线播放 亚洲色大成WWW亚洲女子 | 亚洲国产人成精品| 国产精品99精品久久免费| 欧洲 亚洲 国产图片综合| 国产成人亚洲精品91专区手机| 蜜臀98精品国产免费观看| 午夜亚洲WWW湿好爽| 亚洲邪恶天堂影院在线观看| 免费国产综合视频在线看| 久久永久免费人妻精品| 亚洲av成人一区二区三区在线播放| 亚洲人成伊人成综合网久久久| 一二三四在线播放免费观看中文版视频 | 免费无码av片在线观看| 亚洲人成电影在线观看网| 免费在线不卡视频| 1000部啪啪毛片免费看| 新最免费影视大全在线播放| 老司机亚洲精品影院| 亚洲人成色7777在线观看不卡| 亚洲一区二区三区免费观看| 免费看黄福利app导航看一下黄色录像 | 日韩视频免费在线| 久久精品毛片免费观看| 一区在线免费观看| 亚洲一区二区三区丝袜| 亚洲av不卡一区二区三区| 亚洲AV成人精品日韩一区18p| 亚洲精品免费网站| 国产三级在线免费| 国产精品亚洲精品日韩动图| 亚洲人成在线播放| 亚洲AV一宅男色影视| 亚洲国产高清在线一区二区三区| 日韩av无码成人无码免费| 国产激情免费视频在线观看|