spring學(xué)習(xí)14(AOP面向切面編程)

    1. 要使用aop編程所需要的jar:
      aspectjrt.jar
      aspectjweaver.jar
      commons-logging-1.2.jar
      spring-aop-4.3.9.RELEASE.jar
      spring-aspects-4.3.9.RELEASE.jar
      spring-beans-4.3.9.RELEASE.jar
      spring-context-4.3.9.RELEASE.jar
      spring-core-4.3.9.RELEASE.jar
      spring-expression-4.3.9.RELEASE.jar
  • 2.在配置文件加入aop命名空間

  • 3 把切面加入ioc容器 使用@Component 注解加入spring容器 使用@Aspect標識為切面

  • 4 在切面類中聲明通知如 @Before

  • 5 訪問到方法細節(jié)在通知方法加入?yún)?shù)JoinPoint

注解方式:

模擬計算器 在加減乘除打印日志

定義一個計算器接口

package chen.spring.aop;
public interface calculate {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

計算器實現(xiàn)類并注解方式配置為bean

package chen.spring.aop;

import org.springframework.stereotype.Component;

@Component
public class JiShuanQi implements calculate{
    @Override
    public int add(int i, int j) {
        int r=i+j;
        System.out.println( r);
        return r;
    }

    @Override
    public int sub(int i, int j) {
        int r=i-j;
        System.out.println( r);
        return r;
    }

    @Override
    public int mul(int i, int j) {
        int r=i*j;
        System.out.println( r);
        return r;
    }

    @Override
    public int div(int i, int j) {
        int r=i/j;
        System.out.println( r);
        return r;
    }
}

切面類:

package chen.spring.aop;

import java.util.Arrays;

import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;


//使用@Order注解指定切面右下角 越小優(yōu)先級越高
@Order(1)
@Aspect
@Component
public class LogAspect {
    //定義一個方法风皿,用于聲明切入點表達式舞痰,一般這個方法不需要其他代碼
    //使用@Pointcut來聲明切入點
    //后面的其他通知就可以直接使用方法名來引用當(dāng)前的切入點表達式
    @Pointcut("execution(public int chen.spring.aop.calculate.*(int, int))")
    public void pointcut() {}
    
    
    //聲明前置前置通知:在目標方法之前
//  @Before("execution(public int chen.spring.aop.calculate.*(int, int))")
    @Before("pointcut()")//使用了切入點聲明
    public void beforeLog(JoinPoint jPoint) {
        String name=jPoint.getSignature().getName();//獲取方法name
        List<Object> args=Arrays.asList(jPoint.getArgs());//獲取參數(shù)
        System.out.println("前置通知 方法"+name +"參數(shù)"+args);
        
    }
    
    //后置通知:在目標方法執(zhí)行后(無論發(fā)生錯誤)
    //在后置通知中還不能訪問目標方法的結(jié)果
    @After("execution(public int chen.spring.aop.calculate.*(int, int))")
    public void afterLog(JoinPoint jPoint) {
        String name=jPoint.getSignature().getName();//獲取方法name
        List<Object> args=Arrays.asList(jPoint.getArgs());//獲取參數(shù)
        System.out.println("后置通知 方法"+name +"參數(shù)"+args);
    }
    
    //返回通知:在方法正確執(zhí)行后執(zhí)行的代碼
    //可以訪問返回值
    @AfterReturning(value="execution(public int chen.spring.aop.calculate.*(int, int))",
            returning="result")
    public void afterReturningLog(JoinPoint jPoint,Object result) {
        String name=jPoint.getSignature().getName();//獲取方法name
        List<Object> args=Arrays.asList(jPoint.getArgs());//獲取參數(shù)
        System.out.println("返回通知 方法"+name +" 參數(shù)="+args+" 返回值="+result);
        
    }
    //異常通知:在方法異常后執(zhí)行的代碼
    //可以指定特定異常才執(zhí)行
    @AfterThrowing(value="execution(public int chen.spring.aop.calculate.*(int, int))",
            throwing="ex")
    public void afterThrowingLog(JoinPoint jPoint,Exception ex) {
        String name=jPoint.getSignature().getName();//獲取方法name
        System.out.println("返回通知 方法"+name +" 返回值="+ex);
    }
    
    //環(huán)繞通知:需要ProceedingJoinPoint類型的參數(shù)
    //環(huán)繞通知類似于動態(tài)代理的全程:ProceedingJoinPoint類型的參數(shù)可以決定是否執(zhí)行目標方法
    //且環(huán)繞通知必須有返回值包蓝,返回值即為目標方法的返回值
    @Around("execution(public int chen.spring.aop.calculate.*(int, int))")
    public Object aroundLog(ProceedingJoinPoint point) {
        String name=point.getSignature().getName();
        System.out.println("環(huán)繞通知 方法"+name);
        Object r=null;
        try {
            //前置通知
            r=point.proceed();//執(zhí)行目標方法
            //返回通知
        } catch (Throwable e) {
            //異常通知
            e.printStackTrace();
        }
            //后置通知
        return r;
    }
}


    //1 需要的jar

    /**
    aspectjrt.jar
    aspectjweaver.jar
    commons-logging-1.2.jar
    spring-aop-4.3.9.RELEASE.jar
    spring-aspects-4.3.9.RELEASE.jar
    spring-beans-4.3.9.RELEASE.jar
    spring-context-4.3.9.RELEASE.jar
    spring-core-4.3.9.RELEASE.jar
    spring-expression-4.3.9.RELEASE.jar
     * */
    
    //2 在配置文件加入aop命名空間
    
    //3 把切面加入ioc容器 使用@Component  標識為切面使用@Aspect
    
    //4 在切面類中聲明通知如 @Before
    
    //5 訪問到方法細節(jié)在通知方法加入?yún)?shù)JoinPoint

配置文件 :

<?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: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 http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!--配置自動掃描 -->
<context:component-scan base-package="chen.spring.aop"></context:component-scan>
<!-- 使 aspectj 注解起作用 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>

  • 必須<aop:aspectj-autoproxy/>啟動注解配置
通知:
  • 前置通知:在目標方法之前 使用 @Before(execution(方法的全簽名))可以使用通配符
    //聲明前置前置通知:在目標方法之前
    @Before("execution(public int chen.spring.aop.calculate.*(int, int))")
    public void beforeLog(JoinPoint jPoint) {
        String name=jPoint.getSignature().getName();//獲取方法name
        List<Object> args=Arrays.asList(jPoint.getArgs());//獲取參數(shù)
        System.out.println("前置通知 方法"+name +"參數(shù)"+args);
        
    }
  • 后置通知:在目標方法執(zhí)行后(無論發(fā)生錯誤)并且 后置通知中還不能訪問目標方法的結(jié)果
//后置通知:在目標方法執(zhí)行后(無論發(fā)生錯誤)
    //在后置通知中還不能訪問目標方法的結(jié)果
    @After("execution(public int chen.spring.aop.calculate.*(int, int))")
    public void afterLog(JoinPoint jPoint) {
        String name=jPoint.getSignature().getName();//獲取方法name
        List<Object> args=Arrays.asList(jPoint.getArgs());//獲取參數(shù)
        System.out.println("后置通知 方法"+name +"參數(shù)"+args);
    }
  • 返回通知:在方法正確執(zhí)行后執(zhí)行的代碼 并且可以訪問返回值
//返回通知:在方法正確執(zhí)行后執(zhí)行的代碼
    //可以訪問返回值
    @AfterReturning(value="execution(public int chen.spring.aop.calculate.*(int, int))",
            returning="result")
    public void afterReturningLog(JoinPoint jPoint,Object result) {
        String name=jPoint.getSignature().getName();//獲取方法name
        List<Object> args=Arrays.asList(jPoint.getArgs());//獲取參數(shù)
        System.out.println("返回通知 方法"+name +" 參數(shù)="+args+" 返回值="+result);
        
    }
  • 異常通知:在方法異常后執(zhí)行的代碼 可以指定特定異常才執(zhí)行
    //異常通知:在方法異常后執(zhí)行的代碼
    //可以指定特定異常才執(zhí)行
    @AfterThrowing(value="execution(public int chen.spring.aop.calculate.*(int, int))",
            throwing="ex")
    public void afterThrowingLog(JoinPoint jPoint,Exception ex) {
        String name=jPoint.getSignature().getName();//獲取方法name
        System.out.println("返回通知 方法"+name +" 返回值="+ex);
    }
  • 環(huán)繞通知 環(huán)繞通知:需要ProceedingJoinPoint類型的參數(shù) 環(huán)繞通知類似于動態(tài)代理的全程:ProceedingJoinPoint類型的參數(shù)可以決定是否執(zhí)行目標方法 且環(huán)繞通知必須有返回值蒜哀,返回值即為目標方法的返回值
//環(huán)繞通知:需要ProceedingJoinPoint類型的參數(shù)
    //環(huán)繞通知類似于動態(tài)代理的全程:ProceedingJoinPoint類型的參數(shù)可以決定是否執(zhí)行目標方法
    //且環(huán)繞通知必須有返回值,返回值即為目標方法的返回值
    @Around("execution(public int chen.spring.aop.calculate.*(int, int))")
    public Object aroundLog(ProceedingJoinPoint point) {
        String name=point.getSignature().getName();
        System.out.println("環(huán)繞通知 方法"+name);
        Object r=null;
        try {
            //前置通知
            r=point.proceed();//執(zhí)行目標方法
            //返回通知
        } catch (Throwable e) {
            //異常通知
            e.printStackTrace();
        }
            //后置通知
        return r;
    }
  • 定義一個方法,用于聲明切入點表達式,一般這個方法不需要其他代碼 使用@Pointcut來聲明切入點 后面的其他通知就可以直接使用方法名來引用當(dāng)前的切入點表達式
//定義一個方法苫耸,用于聲明切入點表達式,一般這個方法不需要其他代碼
    //使用@Pointcut來聲明切入點
    //后面的其他通知就可以直接使用方法名來引用當(dāng)前的切入點表達式
    @Pointcut("execution(public int chen.spring.aop.calculate.*(int, int))")
    public void pointcut() {}

    //聲明前置前置通知:在目標方法之前
    @Before("pointcut()")//使用了切入點聲明
    public void beforeLog(JoinPoint jPoint) {
        String name=jPoint.getSignature().getName();//獲取方法name
        List<Object> args=Arrays.asList(jPoint.getArgs());//獲取參數(shù)
        System.out.println("前置通知 方法"+name +"參數(shù)"+args);
        
    }

配置文件方式:

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    <!-- 配置bean -->
    <bean id="jsq" class="chen.spring.aop.JiShuanQi"></bean>
    <!-- 配置切面bean -->
    <bean id="aspect" class="chen.spring.aop.LogAspect"></bean>
    <!-- 配置AOP -->
    <aop:config>
        <!-- 配置切點表達式 -->
        <aop:pointcut
            expression="execution(public int chen.spring.aop.calculate.*(int, int))"
            id="pointcut" />
        <!-- 配置切面 -->
        <aop:aspect ref="aspect" order="1">
            <!-- 配置切面通知 -->
            <aop:before method="afterLog" pointcut-ref="pointcut" />
            <aop:after method="afterLog" pointcut-ref="pointcut" />
        </aop:aspect>
    </aop:config>

</beans>
  • 1.配置bean
  • 2.配置切面bean
  • 3.配置AOP
    1)配置切點表達式 切點
    2)配置切面 關(guān)聯(lián)切面bean
    3)在切面配置中 配置切面通知 以及通知對應(yīng)的方法

總結(jié):

  • 切面類要加入spring容器 并使用@Aspect標識 spring就可以自動識別裝配

  • 當(dāng)目標類方法擁有多個切面時可以在 切面類使用@Order(數(shù)值)注解 數(shù)值越小優(yōu)先級越高 (切面優(yōu)先級)

  • 切面原理 動態(tài)代理

  • 各個通知可以有相應(yīng)的參數(shù) 也可以獲取相應(yīng)的數(shù)據(jù)

  • 切點:需要介入的目標方法 切面:處理對應(yīng)的類 通知:介入目標方法 的介入方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末儡陨,一起剝皮案震驚了整個濱河市褪子,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌迄委,老刑警劉巖褐筛,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異叙身,居然都是意外死亡,警方通過查閱死者的電腦和手機硫狞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門信轿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人残吩,你說我怎么就攤上這事财忽。” “怎么了泣侮?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵即彪,是天一觀的道長。 經(jīng)常有香客問我活尊,道長隶校,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任蛹锰,我火速辦了婚禮深胳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘铜犬。我一直安慰自己舞终,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布癣猾。 她就那樣靜靜地躺著敛劝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纷宇。 梳的紋絲不亂的頭發(fā)上夸盟,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機與錄音呐粘,去河邊找鬼满俗。 笑死转捕,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的唆垃。 我是一名探鬼主播五芝,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼辕万!你這毒婦竟也來了枢步?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤渐尿,失蹤者是張志新(化名)和其女友劉穎醉途,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砖茸,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡隘擎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了凉夯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片货葬。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖劲够,靈堂內(nèi)的尸體忽然破棺而出震桶,到底是詐尸還是另有隱情,我是刑警寧澤征绎,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布蹲姐,位于F島的核電站,受9級特大地震影響人柿,放射性物質(zhì)發(fā)生泄漏柴墩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一顷扩、第九天 我趴在偏房一處隱蔽的房頂上張望拐邪。 院中可真熱鬧,春花似錦隘截、人聲如沸扎阶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽东臀。三九已至,卻和暖如春犀农,著一層夾襖步出監(jiān)牢的瞬間惰赋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赁濒,地道東北人轨奄。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像拒炎,于是被迫代替她去往敵國和親挪拟。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355

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