Spring筆記----Day02----DynamicAgentAndAOP

一盯另、動態(tài)代理(Dynamic agent):

?1癞揉、特點:

字節(jié)碼隨用隨創(chuàng)建久妆,隨用隨加載榆苞。

?2成箫、作用:

在不修改源碼的基礎(chǔ)上對方法增強铆铆。

?3种蝶、分類:

??<1>员萍、基于接口的動態(tài)代理:

??(1)促王、涉及到的類:

Proxy

??(2)掩完、提供者:

JDK官方

??(3)、創(chuàng)建方法:

使用Proxy類中的newProxyInstance方法硼砰。

??(4)且蓬、對代理對象的要求:

被代理對象至少實現(xiàn)一個接口,否則不可用题翰。

??(5)恶阴、newProxyInstance方法的參數(shù):

???①诈胜、ClassLoader:
類加載器
用于加載代理對象的字節(jié)碼,和被代理對象使用相同的類加載器冯事。
固定寫法
???②焦匈、Class[]:
字節(jié)碼數(shù)組
用于讓代理對象和被代理對象擁有相同方法。
固定寫法
???③昵仅、InvocationHandler:
用于提供增強的代碼
用于讓我們代理缓熟,一般是一個該接口的實現(xiàn)類。通常是匿名內(nèi)部類摔笤,但不是必須的够滑。
作用:
    執(zhí)行被代理對象的任何方法都會經(jīng)過該方法。
函數(shù):
    proxy:代理對象的引用吕世。
    method:當前執(zhí)行的方法彰触。
    args:當前執(zhí)行方法所需參數(shù)。
    返回值:和被代理對象擁有相同的返回值命辖。

??<2>况毅、基于子類的動態(tài)代理:

??(1)、涉及到的類:

Enhancer

??(2)尔艇、提供者:

第三方cglib庫

??(3)尔许、創(chuàng)建方法:

使用Enhancer中的create方法。

??(4)终娃、對代理對象的要求:

被代理類不能是最終類味廊。

??(5)、create方法的參數(shù):

???①尝抖、class:
字節(jié)碼
指定被代理類的字節(jié)碼毡们,要代理誰,就用誰.class
???②昧辽、callback:
用于提供增強的代碼
一般使用該接口的一個子接口實現(xiàn)類:MethodInterceptor
函數(shù):
    proxy:代理對象的引用衙熔。
    method:當前執(zhí)行的方法。
    args:當前執(zhí)行方法所需參數(shù)搅荞。
    methodProxy:當前執(zhí)行方法的代理對象红氯。
    返回值:和被代理對象擁有相同的返回值。

二咕痛、面向切面編程(AOP):

1痢甘、作用:

在程序運行期間,不修改源碼茉贡,對已有方法進行增強塞栅。

2、優(yōu)勢:

?<1>腔丧、減少重復(fù)代碼放椰。
?<2>作烟、提高開發(fā)效率。
?<3>砾医、維護方便拿撩。

3、相關(guān)術(shù)語:

?<1>如蚜、Joinpoint(連接點):
指被攔截到的點压恒。在spring中,這些點指的是方法错邦。
因為spring只支持方法類型的連接點探赫。也就是業(yè)務(wù)層的每一個方法。
?<2>兴猩、Pointcut(切入點):
指的是要對哪些Joinpoint進行攔截的定義期吓。也就是業(yè)務(wù)層中被增強的方法早歇。
?<3>倾芝、Advice(通知):
定義:
    指的是攔截到Joinpoint之后要做的事情。
分類:
    前置通知箭跳、后置通知晨另、異常通知、最終通知谱姓、環(huán)繞通知
分類原理:
    以調(diào)用業(yè)務(wù)層方法(被try……catch包裹起來)為界限借尿,在其上面就是前置通知;下面就是后置通知屉来;
    在catch內(nèi)就是異常通知路翻;在finally內(nèi)就是最終通知;整個invoke方法在執(zhí)行時就是環(huán)繞通知茄靠。
?<4>茂契、Introduction(引介):
在不修改類代碼的前提下,Introduction可以在運行期為類動態(tài)的添加一些方法或Field慨绳。
?<5>掉冶、Target(目標對象):
代理的目標對象。
?<6>脐雪、Weaving(織入):
指把增強應(yīng)用到目標對象來創(chuàng)建新的代理對象的過程厌小。
spring采用的是動態(tài)代理織入,而AspectJ采用的是編譯器織入和類加載期織入战秋。
?<7>璧亚、Proxy(代理):
一個類被AOP織入增強后,就產(chǎn)生一個新的結(jié)果代理類脂信。
?<8>癣蟋、Aspect(切面):
切入點和通知(引介)的結(jié)合拐袜。

4、spring中AOP的配置:

<1>梢薪、基于XML的配置:

?(1)蹬铺、把通知Bean交給spring管理
?(2)、使用aop:config標簽表明開始AOP的配置
?(3)秉撇、使用aop:aspect標簽表明配置切面
id屬性:給切面提供一個唯一標識
ref屬性:指定通知類bean的標簽
?(4)甜攀、在aop:aspect標簽內(nèi)部使用對應(yīng)標簽來配置通知
前置通知:aop:before
    method屬性:用于指定Logger類中哪個方法是前置通知。
    pointcut屬性:用于指定切入點表達式琐馆,該表達式的含義指的是對業(yè)務(wù)層哪些方法增強规阀。

后置通知:aop:after-returning
    method屬性:用于指定Logger類中哪個方法是前置通知。
    pointcut屬性:用于指定切入點表達式瘦麸,該表達式的含義指的是對業(yè)務(wù)層哪些方法增強谁撼。

異常通知:aop:after-throwing
    method屬性:用于指定Logger類中哪個方法是前置通知。
    pointcut屬性:用于指定切入點表達式滋饲,該表達式的含義指的是對業(yè)務(wù)層哪些方法增強厉碟。

最終通知:aop:after
    method屬性:用于指定Logger類中哪個方法是前置通知。
    pointcut屬性:用于指定切入點表達式屠缭,該表達式的含義指的是對業(yè)務(wù)層哪些方法增強箍鼓。

切入點表達式:
關(guān)鍵字:execution(表達式)
    表達式:
        訪問修飾符 返回值 包名.包名...包名.類名.方法名(參數(shù)列表)
    eg:
        標準寫法:
            public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
        訪問修飾符可以省略:
            void com.itheima.service.impl.AccountServiceImpl.saveAccount()
        返回值可以采用通配符*表示返回任意值
            * com.itheima.service.impl.AccountServiceImpl.saveAccount()
        包名可以采用通配符*表示任意包;注意:有幾集包就需要寫幾個*呵曹,中間以.隔開款咖。
            * *.*.*.*.AccountServiceImpl.saveAccount()
        包名也可以使用..表示當前包及其子包
            * *..AccountServiceImpl.saveAccount()
        類名可以采用通配符*實現(xiàn)通配:
            * *..*.saveAccount()
        方法名可以采用通配符*實現(xiàn)通配:
            * *..*.*()
        參數(shù)列表:
            可以直接寫數(shù)據(jù)類型:
                基本類型直接寫名稱           int
                引用類型寫包名.類名的方式     java.long.String
            可以使用通配符*表示任意類型,但是必須有參數(shù)
            可以使用..表示有無參數(shù)均可奄喂,有參數(shù)可以是任意類型
            通配符寫法:
                * *..*.*(..)
            實際開發(fā)中铐殃,切入點表達式的通常寫法:
                切入到業(yè)務(wù)層實現(xiàn)類下的所有方法。
<!--配置AOP-->
    <aop:config>
        <!--配置切面-->
        <aop:aspect id="logAdvice" ref="logger">

            <!--配置前置通知,在切入點方法執(zhí)行之前執(zhí)行-->
            <aop:before method="beforePrintLog" pointcut="execution(* *..*.*(..))"></aop:before>

            <!--配置后置通知,在切入點方法執(zhí)行之后執(zhí)行-->
            <aop:after-returning method="afterReturnPrintLog" pointcut="execution(* *..*.*(..))"></aop:after-returning>

            <!--配置異常通知,在切入點方法執(zhí)行產(chǎn)生異常之后執(zhí)行-->
            <aop:after-throwing method="afterThrowingPrintLog" pointcut="execution(* *..*.*(..))"></aop:after-throwing>

            <!--配置最終通知,無論切入點方法是否執(zhí)行跨新,它都會在其后執(zhí)行-->
            <aop:after method="afterPrintLog" pointcut="execution(* *..*.*(..))"></aop:after>
        </aop:aspect>
    </aop:config>
<!--配置AOP-->
    <aop:config>

        <!--配置切入點表達式富腊,id屬性用于指定表達式的唯一標識,expression屬性用于指定表達式內(nèi)容玻蝌。
            此標簽寫在aop:pointcut標簽外部時蟹肘,只能寫在<aop:pointcut>標簽上面,<aop:config標簽下面俯树;可以在所有切面使用帘腹。
        -->
        <aop:pointcut id="pt1" expression="execution(* *..*.*(..))"></aop:pointcut>

        <!--配置切面-->
        <aop:aspect id="logAdvice" ref="logger">

            <!--配置前置通知,在切入點方法執(zhí)行之前執(zhí)行-->
            <aop:before method="beforePrintLog" pointcut-ref="pt1"></aop:before>

            <!--配置后置通知,在切入點方法執(zhí)行之后執(zhí)行,它和異常通知兩者只會執(zhí)行一個-->
            <aop:after-returning method="afterReturnPrintLog" pointcut-ref="pt1"></aop:after-returning>

            <!--配置異常通知,在切入點方法執(zhí)行產(chǎn)生異常之后執(zhí)行许饿,它和后置通知兩者只會執(zhí)行一個-->
            <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>

            <!--配置最終通知,無論切入點方法是否執(zhí)行阳欲,它都會在其后執(zhí)行-->
            <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>
        </aop:aspect>
    </aop:config>
?(5)、配置環(huán)繞通知:
環(huán)繞通知:aop:before
    它是spring框架提供的一種可以在代碼中手動控制增強方法何時執(zhí)行的方式。
    問題:當配置了環(huán)繞通知之后球化,切入點方法沒有執(zhí)行秽晚,而通知方法執(zhí)行了。
    分析:對比動態(tài)代理中的環(huán)繞通知代碼筒愚,發(fā)現(xiàn)動態(tài)代理的環(huán)繞通知中有明確的
         切入點方法調(diào)用赴蝇,而此處的代碼中沒有。
    解決:Spring框架提供了一個接口:ProceedingJoinPoint巢掺。該接口中有一個
         方法proceed()句伶,此方法就相當于明確調(diào)用切入點方法。該接口可以作為
         環(huán)繞通知的方法參數(shù)陆淀,在程序執(zhí)行時考余,Spring框架會為我們提供該接口的實現(xiàn)類供我們使用。
 <aop:config>

        <!--配置切入點表達式轧苫,id屬性用于指定表達式的唯一標識楚堤,expression屬性用于指定表達式內(nèi)容。
            此標簽寫在aop:pointcut標簽外部時含懊,只能寫在<aop:pointcut>標簽上面身冬,<aop:config標簽下面;可以在所有切面使用绢要。
        -->
        <aop:pointcut id="pt1" expression="execution(* *..*.*(..))"></aop:pointcut>

        <!--配置切面-->
        <aop:aspect id="logAdvice" ref="logger">
        
        <!--配置環(huán)繞通知-->
        <aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
        
        </aop:aspect>
    </aop:config>
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
public class Logger {
    
    /**
     * 環(huán)繞通知
     */
    public Object aroundPringLog(ProceedingJoinPoint pjp){
        Object rtValue = null;
        try {
            //得到方法執(zhí)行所需的參數(shù)
            Object[] args = pjp.getArgs();

            System.out.println("Logger類中的aroundPringLog方法開始記錄日志@艄А^中 重罪!前置通知");

            //明確調(diào)用業(yè)務(wù)層方法(切入點方法)
            rtValue = pjp.proceed(args);

            System.out.println("Logger類中的aroundPringLog方法開始記錄日志!0Ь拧剿配!后置通知");

            return rtValue;
        }catch (Throwable t){
            System.out.println("Logger類中的aroundPringLog方法開始記錄日志!T氖呼胚!異常通知");
            throw new RuntimeException(t);
        }finally {
            System.out.println("Logger類中的aroundPringLog方法開始記錄日志!O⒙恪蝇更!最終通知");
        }
    }
}
?(5)、五種通知的分類依據(jù):

<1>呼盆、基于注解的配置:

(1)年扩、相關(guān)約束:

    <!--配置spring創(chuàng)建容器時要掃描的包-->
    <context:component-scan base-package="com.itheima"></context:component-scan>

    <!--配置Spring開啟注解AOP的支持-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

(2)、相關(guān)注解:

①访圃、@Aspect:
將"<aop:aspect id="logAdvice" ref="logger"></aop:aspect>"替換成
實現(xiàn)類上的注解@Aspect厨幻,表示當前類是一個切面。
②、@Pointcut:
將"<aop:pointcut id="pt1" expression="execution(* *..*.*(..))"></aop:pointcut>"
替換成方法上的注解
@Pointcut("execution(* *..*.*(..))")
private void pt1(){}
③况脆、@Before("pt1()"):
前置通知饭宾,注解在前置通知的實現(xiàn)方法上,替換
"<aop:before method="beforePrintLog" pointcut-ref="pt1"></aop:before>"
注解的參數(shù)指的是切入點表達式注解的方法的方法名格了。
④看铆、@AfterReturning("pt1()"):
后置通知,注解在后置通知的實現(xiàn)方法上盛末,替換
"<aop:after-returning method="afterReturnPrintLog" pointcut-ref="pt1"></aop:after-returning>"
注解的參數(shù)指的是切入點表達式注解的方法的方法名性湿。
⑤、@AfterThrowing("pt1()"):
異常通知满败,注解在異常通知的實現(xiàn)方法上肤频,替換
"<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>"
注解的參數(shù)指的是切入點表達式注解的方法的方法名。
⑥算墨、@After("pt1()"):
最終通知宵荒,注解在最終通知的實現(xiàn)方法上,替換
"<aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>"
注解的參數(shù)指的是切入點表達式注解的方法的方法名净嘀。
⑦报咳、@Around("pt1()"):
環(huán)繞通知,注解在環(huán)繞通知的實現(xiàn)方法上挖藏,替換
"<aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>"
注解的參數(shù)指的是切入點表達式注解的方法的方法名暑刃。
⑧、特別注意:
Spring基于注解的通知膜眠,有順序調(diào)用的問題岩臣,采用注解時,
后置通知/異常通知會在最終通知之后執(zhí)行宵膨;而采用環(huán)繞通知時架谎,就不會有順序問題。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辟躏,一起剝皮案震驚了整個濱河市谷扣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捎琐,老刑警劉巖会涎,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異瑞凑,居然都是意外死亡末秃,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門拨黔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛔溃,“玉大人绰沥,你說我怎么就攤上這事『卮” “怎么了徽曲?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長麸塞。 經(jīng)常有香客問我秃臣,道長,這世上最難降的妖魔是什么哪工? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任奥此,我火速辦了婚禮,結(jié)果婚禮上雁比,老公的妹妹穿的比我還像新娘稚虎。我一直安慰自己,他們只是感情好偎捎,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布蠢终。 她就那樣靜靜地躺著,像睡著了一般茴她。 火紅的嫁衣襯著肌膚如雪寻拂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天丈牢,我揣著相機與錄音祭钉,去河邊找鬼。 笑死己沛,一個胖子當著我的面吹牛慌核,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播泛粹,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼遂铡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了晶姊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤伪货,失蹤者是張志新(化名)和其女友劉穎们衙,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碱呼,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蒙挑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了愚臀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忆蚀。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出馋袜,到底是詐尸還是另有隱情男旗,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布欣鳖,位于F島的核電站察皇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏泽台。R本人自食惡果不足惜什荣,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望怀酷。 院中可真熱鬧稻爬,春花似錦、人聲如沸蜕依。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笔横。三九已至竞滓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吹缔,已是汗流浹背商佑。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留厢塘,地道東北人茶没。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像晚碾,于是被迫代替她去往敵國和親抓半。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

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