AOP面向切面!!!!!!!!!

知識(shí)點(diǎn)補(bǔ)充

  • 動(dòng)態(tài)代理:增強(qiáng)業(yè)務(wù)功能冀续,兩種實(shí)現(xiàn)方式
    1.JDK動(dòng)態(tài)代理:Proxy涮瞻,Method绣版,inovcationHandler 要求目標(biāo)對(duì)象必須有接口胶台。可以在程序執(zhí)行過程中杂抽,創(chuàng)建代理對(duì)象。通過代理對(duì)象執(zhí)行方法韩脏,給目標(biāo)類的方法增加額外的功能(功能增強(qiáng))
  • 作用:
  1. 在目標(biāo)源代碼不變的情況下缩麸,增加功能。
  2. 減少代碼的重復(fù)
  3. 專注業(yè)務(wù)邏輯代碼
  4. 解耦合赡矢,讓業(yè)務(wù)功能和非業(yè)務(wù)功能分離杭朱。
  • service類
public class MyInvocationHandler implements InvocationHandler {
    private SomeService target ;

    public MyInvocationHandler(SomeService target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ServiceTools.logs();
        Object invoke = method.invoke(target, args);
        ServiceTools.fq();
        return invoke;
    }
}

  • 工具類 業(yè)務(wù)增強(qiáng)
public class ServiceTools {
    public static void logs(){
        System.out.println("增加功能1");
    }
    public static void fq(){
        System.out.println("增加功能2");
    }
}

  • 代理類 MyInvocationHandler
public class MyInvocationHandler implements InvocationHandler {
    private SomeService target ;

    public MyInvocationHandler(SomeService target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ServiceTools.logs();
        Object invoke = method.invoke(target, args);
        ServiceTools.fq();
        return invoke;
    }
}

  • 通過代理調(diào)用
public class MyApp {
    public static void main(String[] args) {
        //創(chuàng)建目標(biāo)對(duì)象
        SomeService1 target = new SomeService1();
        // 創(chuàng)建InvocationHandler對(duì)象
        MyInvocationHandler handler = new MyInvocationHandler(target);
        // 使用proxy創(chuàng)建動(dòng)態(tài)代理
        SomeService o = (SomeService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                handler
        );
        // 通過代理來調(diào)用方法
        o.doSome();
        o.doOther();
    }
}

2.CGLIB代理:通過繼承重寫父類的方法。

AOP面向切面編程

什么是aop吹散?(其實(shí)就動(dòng)態(tài)代理的規(guī)范化)

  • 底層實(shí)現(xiàn)就是動(dòng)態(tài)代理

oop:面向?qū)ο缶幊袒⌒担秧?xiàng)目中的功能拆分成不同的類。

怎么理解面向切面編程空民?

  • Aspect: 切面刃唐,給你的目標(biāo)類增加的功能就是切面羞迷。
    切面的特點(diǎn):一般都是非業(yè)務(wù)方法,獨(dú)立使用
  • Orient: 面向画饥,對(duì)象衔瓮。
  • Programming: 編程。

分析面向切面(面試回答)

  • 在分析項(xiàng)目功能時(shí)抖甘,找出切面热鞍。
  • 合理安排切面的執(zhí)行時(shí)間
  • 合理的安排切面的位置,哪個(gè)類衔彻,哪個(gè)方法增強(qiáng)功能薇宠。

術(shù)語

  • Aspact:切面,表示增強(qiáng)功能艰额,就是一堆代碼昼接,完成某一功能,非業(yè)務(wù)功能悴晰,常見的切面功能由日志慢睡,事物,統(tǒng)計(jì)信息铡溪,權(quán)限漂辐。
  • JoinPiont:連接點(diǎn),連接業(yè)務(wù)方法和切面的位置棕硫。就某類中的業(yè)務(wù)方法髓涯。 一個(gè)方法
  • Pointcut:切入點(diǎn),?多個(gè)連接點(diǎn)方法的集合哈扮。多個(gè)方法
  • 目標(biāo)對(duì)象:給哪個(gè)類的方法增加功能纬纪,這個(gè)類就是目標(biāo)對(duì)象
  • Advice:通知,通知表示切面功能執(zhí)行的時(shí)間滑肉。

三個(gè)關(guān)鍵要輸:

  • 切面的功能
  • 切面的執(zhí)行位置 : Pointcut 切入點(diǎn)
  • 切面的執(zhí)行時(shí)間 : Advice 通知

Spring的aop實(shí)現(xiàn)框架:

  • aop的技術(shù)實(shí)現(xiàn):
    1.spring: spring在內(nèi)部實(shí)現(xiàn)了aop的規(guī)范包各,能做aop的工作。
    spring主要在事物處理時(shí)使用aop靶庙。
    我們項(xiàng)目開發(fā)中很少使用spring的aop實(shí)現(xiàn)问畅,因?yàn)閟pring的aop比較笨重
    2.aspectJ: 一個(gè)開源的專門做aop的框架。(主要用他實(shí)現(xiàn)的aop)六荒,spring框架中集成了aspectJ的框架护姆,通過spring就能使用aspectJ的功能。
    aspectJ實(shí)現(xiàn)aop由兩種方式:
    使用xml的配置文件
    使用注解掏击,我們?cè)陧?xiàng)目中要做aop功能卵皂,一般使用注解,aspectJ由5個(gè)注解砚亭。

aspectJ的使用

  • 切面的執(zhí)行時(shí)間灯变,在規(guī)范中叫做通知(Advice)殴玛,國內(nèi)翻譯增強(qiáng)。
    在aspectj框架中使用注解表示的柒凉。
    1.@Before
    2.@AfterRetruning
    3.@Around
    4.@AfterThrowing
    5.@After
  • 表示切面執(zhí)行的位置族阅,使用的時(shí)切入點(diǎn)表達(dá)式
    execution(訪問權(quán)限? 方法返回值類型 方法的聲明 異常類型?)
    由問號(hào)的可有可沒有
  • 通配符
    * 表示任意字符
    ..用在方法參數(shù)中表示任意多個(gè)參數(shù)膝捞, 在包名后面寶石當(dāng)前包及其子包路徑坦刀。
    +用在類名后,表示當(dāng)前類及其子類蔬咬,用在接口后鲤遥,表示當(dāng)前接口及其實(shí)現(xiàn)類。
    例如:
execution(public * * (..))
指定任意公共方法
execution(* set*(..))
指定切入點(diǎn)為任何一個(gè)以set開頭的方法
execution(* com.xyz.service.*.*(..))
表示com.xyz.service包下的所有類的所有方法

使用aspect實(shí)現(xiàn)aop的基本步驟

  1. 新建maven項(xiàng)目
  2. 加入依賴
    spring依賴
    aspectj依賴
    junit單元測(cè)試
  3. 創(chuàng)建目標(biāo)類:接口和他的實(shí)現(xiàn)類
    要做是給類中的放啊增加方法
  4. 增加切面類:普通類
    在類的上面加入@Aspect
    在類中定義方法林艘,方法就是切面要執(zhí)行的功能代碼
    在方法的上面加入aspectj中的通知注解盖奈,例如@Before
    有需要指定切入點(diǎn)表達(dá)式execution()
  5. 創(chuàng)建spring的配置文件:聲明對(duì)象,把對(duì)像交給容器統(tǒng)一管理
    可以使用注解或xml配置文件
    1. 聲明目標(biāo)對(duì)象
    2. 聲明切面類對(duì)象
    3. 聲明Aspectj框架中的自動(dòng)代理生成器標(biāo)簽狐援。
      自動(dòng)代理生成器:用來完成對(duì)象的自動(dòng)創(chuàng)建功能的钢坦。
  6. 創(chuàng)建對(duì)象,從spring中獲取對(duì)象啥酱,通過代理執(zhí)行方法爹凹。
  • SomeServiceImpl
public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome(String str) {
        System.out.println(str + "doSome");
    }
}

  • MyAspect
/**
 * 是一個(gè)切面:目的是增強(qiáng)目標(biāo)類的業(yè)務(wù)功能
 */
@Aspect
public class MyAspect {
    /**
     * 定義方法 方法是實(shí)現(xiàn)切面功能的
     *  方法的定義要求:
     *      1. 公共方法 public
     *      2. 方法沒有返回值
     *      3. 方法名稱自定義
     *      4. 方法可以有參數(shù), 也可以沒有參數(shù)
     *         如果有參數(shù),參數(shù)不是自定義的,有幾個(gè)參數(shù)類型可以使用
     */
    /**
     * @Before 前置通知
     *  value 是切入點(diǎn)表達(dá)式切面功能執(zhí)行的位置
     *   在方法的上面
     *   特點(diǎn):
     *   在目標(biāo)方法之前執(zhí)行
     */
    @Before(value = "execution(public void com.lz.bg01.SomeServiceImpl.doSome(String))")
    public void myBefore(){
        System.out.println("Before通知");
    }
}

  • config xml配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--    聲明目標(biāo)對(duì)象-->
    <bean id="someService" class="com.lz.bg01.SomeServiceImpl"/>
<!--    聲明切面類-->
    <bean id="myAspect" class="com.lz.bg01.MyAspect"/>
<!--    聲明目標(biāo)代理生成器:使用aspectj框架內(nèi)部的功能,創(chuàng)建目標(biāo)對(duì)象的代理對(duì)象镶殷。-->
<!--    創(chuàng)建代理對(duì)象是在內(nèi)存中實(shí)現(xiàn)的禾酱,修改目標(biāo)對(duì)象的內(nèi)存中的結(jié)構(gòu)。創(chuàng)建為代理對(duì)象所以目標(biāo)對(duì)象就是被修改后的代理對(duì)象-->
<!--    aspectj-autoproxy:會(huì)吧spring中的對(duì)象根據(jù)指定自動(dòng)生成代理-->
    <aop:aspectj-autoproxy />
</beans>

  • test類

public class MyTest {
    @Test
    public void Test(){
        String config = "config/ApplicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        SomeService service = (SomeService) ac.getBean("someService");
        service.doSome("haha");
    }
}

  • <aop:aspectj-autoproxy /> 自動(dòng)生成代理

什么時(shí)候使用aop技術(shù)绘趋?

當(dāng)你要給項(xiàng)目中颤陶,增加功能,但有不能修改源碼的情況陷遮,可以使用aop滓走。
給業(yè)務(wù)增加事務(wù),日志輸出

  • @JoinPiont 連接點(diǎn)
    代表業(yè)務(wù)方法拷呆,要加入切面功能的業(yè)務(wù)方法
    作用是: 可以在通知方法中獲取方法執(zhí)行時(shí)的信息闲坎, 如果你想在切面功能中用到方法的信息,就加入JoinPoint
   @Before(value = "execution(public void com.lz.bg01.SomeServiceImpl.doSome(String))")
    public void myBefore(JoinPoint jp){
        System.out.println(jp.getSignature());
        System.out.println(jp.getSignature().getName());
        System.out.println("Before通知");
    }

后置通知 @AfterReturning

 /**
     *  后置通知定義方法:方法是實(shí)現(xiàn)切面功能的茬斧。
     *  方法的定義要求:
     *  1.公共方法 public
     *  2.方法沒有返回值
     *  3.方法名稱自定義
     *  4.方法有參數(shù)的,推薦是Object 梗逮,參數(shù)名自定義
     * @AfterReturning : 后置通知
     *     屬性:1.value 切入點(diǎn)表達(dá)式
     *          2.returning 自定義的變量项秉,表示目標(biāo)方法的返回值的。
     *          自定以變量名必須何通知方法的形參名一樣
     *     位置:在方法定義的上面
     *     特點(diǎn):
     *          1.在目標(biāo)方法之后執(zhí)行的慷彤。
     *          2.能夠獲取到目標(biāo)方法的返回值娄蔼,可以根據(jù)這個(gè)返回值做不同的處理功能
     *          3.可以修改這個(gè)返回值
     */
    //    res要相同
    @AfterReturning(value = "execution(public String com.lz.SomeServiceImpl.dothre(..))", returning = "res")
    public void myAfterReturn(Object res){
        System.out.println("后置通知獲取的返回值 "+ res);
    }

環(huán)繞通知

  • 前三個(gè)通知常用 需要掌握
/**
     * @Around :
     *      屬性: value 切入點(diǎn)表達(dá)式
     *      位置:在方法的定義什么
     *    特點(diǎn):
     *      1.它是功能最強(qiáng)的通知
     *      2.在目標(biāo)方法的前和后都能增強(qiáng)功能
     *      3.控制目標(biāo)方法知否被調(diào)用執(zhí)行
     *      4.修改原來的目標(biāo)方法的執(zhí)行結(jié)果怖喻。 影響最后的調(diào)用結(jié)果
     *    環(huán)繞通知,等同于動(dòng)態(tài)代理 : InvocationHandler
     *    ProceedingJoinPoin 等同于 method 執(zhí)行目標(biāo)方法
     *    返回值: 就是目標(biāo)方法的結(jié)果可以被修改
     */

    @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("修改東西");
        Object proceed = proceedingJoinPoint.proceed(); // 相當(dāng)于 doFirst();
        System.out.println("提交事物");
        return proceed;
    }

異常通知 @AfterThrowing

@AfterThrowing(value = "execution(* *..SomeServiceImpl.doFirst())", throwing = "e")
    public void myAfterThrowing(Exception e){
        System.out.println(e.getStackTrace());
    }

最終通知 @After

  • 最終通知像finally岁诉, 就算有異常也會(huì)執(zhí)行锚沸,總是會(huì)被執(zhí)行。
    @After(value = "execution(* *..SomeServiceImpl.diFirst())")
    public void myAfter(){
        System.out.println("最終通知");
    }

PointCut 切入點(diǎn)

在方法上使用@PointCut可以設(shè)置,這個(gè)方法的名稱就是切入點(diǎn)表達(dá)式的別名涕癣,其他的通知中哗蜈,就可以使用這個(gè)別名找到這個(gè)方法。

  @Pointcut(value = "execution(* *.SomeServiceImpl.doFirst(..))")
    public void mypt(){
        
    }
@After(value =“mypt()”)
  • 沒有接口aop用的是cglib的動(dòng)態(tài)代理坠韩,有接口用的是jdk的動(dòng)態(tài)代理Proxy
  • 沒有接口也能用cglib動(dòng)態(tài)代理
    <aop:aspectj-autoproxy proxy-target-class="true"/>
有接口使用cglib這樣設(shè)置
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末距潘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子只搁,更是在濱河造成了極大的恐慌音比,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,686評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件氢惋,死亡現(xiàn)場離奇詭異洞翩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)焰望,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門骚亿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人柿估,你說我怎么就攤上這事循未。” “怎么了秫舌?”我有些...
    開封第一講書人閱讀 158,160評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵的妖,是天一觀的道長。 經(jīng)常有香客問我足陨,道長嫂粟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,736評(píng)論 1 284
  • 正文 為了忘掉前任墨缘,我火速辦了婚禮星虹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘镊讼。我一直安慰自己宽涌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,847評(píng)論 6 386
  • 文/花漫 我一把揭開白布蝶棋。 她就那樣靜靜地躺著卸亮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪玩裙。 梳的紋絲不亂的頭發(fā)上兼贸,一...
    開封第一講書人閱讀 50,043評(píng)論 1 291
  • 那天段直,我揣著相機(jī)與錄音,去河邊找鬼溶诞。 笑死鸯檬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的螺垢。 我是一名探鬼主播喧务,決...
    沈念sama閱讀 39,129評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼甩苛!你這毒婦竟也來了蹂楣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,872評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤讯蒲,失蹤者是張志新(化名)和其女友劉穎痊土,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體墨林,經(jīng)...
    沈念sama閱讀 44,318評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赁酝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,645評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了旭等。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酌呆。...
    茶點(diǎn)故事閱讀 38,777評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖搔耕,靈堂內(nèi)的尸體忽然破棺而出隙袁,到底是詐尸還是另有隱情,我是刑警寧澤弃榨,帶...
    沈念sama閱讀 34,470評(píng)論 4 333
  • 正文 年R本政府宣布菩收,位于F島的核電站,受9級(jí)特大地震影響鲸睛,放射性物質(zhì)發(fā)生泄漏娜饵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評(píng)論 3 317
  • 文/蒙蒙 一官辈、第九天 我趴在偏房一處隱蔽的房頂上張望箱舞。 院中可真熱鬧,春花似錦拳亿、人聲如沸晴股。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽队魏。三九已至,卻和暖如春万搔,著一層夾襖步出監(jiān)牢的瞬間胡桨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評(píng)論 1 267
  • 我被黑心中介騙來泰國打工瞬雹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留昧谊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,589評(píng)論 2 362
  • 正文 我出身青樓酗捌,卻偏偏與公主長得像呢诬,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胖缤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,687評(píng)論 2 351