說(shuō)說(shuō)在 Spring 中如何自動(dòng)創(chuàng)建代理

Spring 提供了自動(dòng)代理機(jī)制,可以讓容器自動(dòng)生成代理萄金,從而把開(kāi)發(fā)人員從繁瑣的配置中解脫出來(lái) 建瘫。 具體是使用 BeanPostProcessor 來(lái)實(shí)現(xiàn)這項(xiàng)功能。

1 BeanPostProcessor

BeanPostProcessor 代理創(chuàng)建器的實(shí)現(xiàn)類可以分為 3 類:

類型 實(shí)現(xiàn)類
基于 Bean 配置名規(guī)則 BeanNameAutoProxyCreator
基于 Advisor 匹配規(guī)則 DefaultAdvisorAutoProxyCreator
基于 Bean 中的 AspectJ 注解標(biāo)簽的匹配規(guī)則 AnnotationAwareAspectJAutoProxyCreator
BeanPostProcessor 類繼承關(guān)系

所有的自動(dòng)代理器類都實(shí)現(xiàn)了 BeanPostPorcessor 荤牍,在容器實(shí)例化 Bean 時(shí)案腺, BeanPostProcessor 將對(duì)它進(jìn)行加工處理,所以自動(dòng)代理創(chuàng)建器能夠?qū)M足匹配規(guī)則的 bean 自動(dòng)創(chuàng)建代理對(duì)象康吵。

2 BeanNameAutoProxyCreator

假設(shè)有以下兩個(gè)實(shí)體類(用戶與充電寶)劈榨。

用戶類:

public class User {

    public void rent(String userId) {
        System.out.println("User:租賃【充電寶】");
    }

    public void back(String userId){
        System.out.println("User:歸還【充電寶】");

    }
}

充電寶:

public class Charger {

    public void rent(String userId) {
        System.out.println("Charger:【充電寶】被租賃");
    }
}

我們希望通過(guò) BeanNameAutoProxyCreator 通過(guò) Bean 的名稱來(lái)自動(dòng)創(chuàng)建代理,實(shí)現(xiàn)增強(qiáng):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

    <bean id="user" class="net.deniro.spring4.aop.User"/>
    <bean id="charger" class="net.deniro.spring4.aop.Charger"/>

    <!-- 前置增強(qiáng)-->
    <bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/>

    <!-- 使用 BeanNameAutoProxyCreator-->
    <bean
            class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
            p:beanNames="*er"
            p:interceptorNames="rentBeforeAdvice"
            p:optimize="true"
            ></bean>
</beans>

BeanNameAutoProxyCreator的 beanNames 屬性允許指定一組需要自動(dòng)代理的 Bean 名稱晦嵌, 這里可以使用 * 通配符 同辣。

因?yàn)槲覀冃枰淼念惷謩e是 user 與 charger,都是以 er 結(jié)尾的惭载,所以我們這里定義為 *er旱函。

也可以通過(guò) beanNames 的 value 值來(lái)明確指定需要代理的 Bean 名稱,多個(gè)以逗號(hào)分隔(更常用)描滔。

<!-- 指定自動(dòng)代理的 Bean 名稱-->
<property name="beanNames" value="user,charger">
</property>

也可以通過(guò) list 方式來(lái)指定 beanNames 的值:

<property name="beanNames">
    <list>
        <value>user</value>
        <value>charger</value>
    </list>
</property>

p:optimize 設(shè)置為 true棒妨,則表示使用 CGLib 動(dòng)態(tài)代理技術(shù)。

通過(guò)這樣的配置之后含长,容器在創(chuàng)建 user 和 charger Bean 的實(shí)例時(shí)靶衍,就會(huì)自動(dòng)為它們創(chuàng)建代理對(duì)象,而這一操作對(duì)于使用者來(lái)說(shuō)完全是透明的 茎芋。

單元測(cè)試:

User user = (User) context.getBean("user");
Charger charger = (Charger) context.getBean("charger");

String userId = "001";
user.rent(userId);
charger.rent(userId);

輸出結(jié)果:

準(zhǔn)備租賃的用戶 ID:001
User:租賃【充電寶】
準(zhǔn)備租賃的用戶 ID:001
Charger:【充電寶】被租賃

3 DefaultAdvisorAutoProxyCreator

切面 Advisor 是切點(diǎn)和增強(qiáng)的復(fù)合體颅眶,而 DefaultAdvisorAutoProxyCreator 能夠掃描 Advisor, 并將 Advisor 自動(dòng)織入到匹配的目標(biāo) Bean 中。

<bean id="user" class="net.deniro.spring4.aop.User"/>
<bean id="charger" class="net.deniro.spring4.aop.Charger"/>

<!-- 前置增強(qiáng)-->
<bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/>

<!-- 靜態(tài)正則表達(dá)式方法名匹配-->
<bean id="regexpAdvisor"
      class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
      p:advice-ref="rentBeforeAdvice">
    <!-- 匹配模式-->
    <property name="patterns">
        <list>
            <!-- 匹配字符串-->
            <value>.*rent.*</value>
        </list>
    </property>
</bean>

<!-- 使用 DefaultAdvisorAutoProxyCreator-->
<bean
        class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

首先我們配置了以靜態(tài)正則表達(dá)式方法名匹配的切面田弥,然后直接配置了 DefaultAdvisorAutoProxyCreator Bean涛酗。

測(cè)試代碼與輸出結(jié)果與上一小節(jié)的 BeanNameAutoProxyCreator 相同。


JDK 動(dòng)態(tài)代理是通過(guò)接口來(lái)實(shí)現(xiàn)方法攔截偷厦,所以必須確保要攔截的目標(biāo)在接口中有定義商叹。

CGLib 動(dòng)態(tài)代理是通過(guò)動(dòng)態(tài)生成代理子類來(lái)實(shí)現(xiàn)方法攔截,所以必須確保要攔截的目標(biāo)方法可以被子類所訪問(wèn)只泼,也就是目標(biāo)方法必須定義為非 final, 且非私有實(shí)例方法 剖笙。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市请唱,隨后出現(xiàn)的幾起案子弥咪,更是在濱河造成了極大的恐慌过蹂,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件聚至,死亡現(xiàn)場(chǎng)離奇詭異酷勺,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)扳躬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)脆诉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人贷币,你說(shuō)我怎么就攤上這事击胜。” “怎么了役纹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵潜的,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我字管,道長(zhǎng)啰挪,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任嘲叔,我火速辦了婚禮亡呵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘硫戈。我一直安慰自己锰什,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布丁逝。 她就那樣靜靜地躺著汁胆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霜幼。 梳的紋絲不亂的頭發(fā)上嫩码,一...
    開(kāi)封第一講書(shū)人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音罪既,去河邊找鬼铸题。 笑死,一個(gè)胖子當(dāng)著我的面吹牛琢感,可吹牛的內(nèi)容都是我干的丢间。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼驹针,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼烘挫!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起柬甥,我...
    開(kāi)封第一講書(shū)人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤饮六,失蹤者是張志新(化名)和其女友劉穎其垄,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喜滨,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年撤防,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了虽风。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寄月,死狀恐怖辜膝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情漾肮,我是刑警寧澤厂抖,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站克懊,受9級(jí)特大地震影響忱辅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谭溉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一墙懂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扮念,春花似錦损搬、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至弄匕,卻和暖如春颅悉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背迁匠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工签舞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人柒瓣。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓儒搭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親芙贫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子搂鲫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容