spring中AspectJ的使用


AspectJ:

什么是AOP:

AOP為Aspect Oriented Programming,意為:面向切面編程;它是一種思想一種設計典范(同Ioc);它是OOP(面向對象編程)的一種衍生。通過AOP對業務邏輯進行隔離,可以降低各個業務邏輯之間的耦合度。AOP主要解決的是”系統及服務“和”主業務邏輯“之間的耦合;

AOP和AspctJ:

AspecJ是一個基於java的AOP框架;spring自身也實現了AOP,在spring中一般使用AspectJ;

關系:AspectJ是AOP思想的實現,AOP實現方式有很多,著名的有spring AOP ,AspectJ;

AOP術語

  1. 目標類(target):需要被增強的類;

  2. 連接點(joinpoint):是指可以被增強到的方法;

  3. 切入點(Pointcut):已經被增強的方法(屬於連接點中的方法)

  4. 通知(advice):指被增強的內容;

  5. 切面(Aspect):切面=切入點+通知;

  6. 織入(weaving):把“通知”應用到“目標類”中的過程;

通知的類型

  • before:前置通知(應用:各種校驗)
    • 在方法執行前執行,如果通知拋出異常,阻止方法運行
  • afterReturning:后置通知(應用:常規數據處理)
    • 方法正常返回后執行,如果方法中拋出異常,通知無法執行
    • 必須在方法執行后才執行,所以可以獲得方法的返回值。
  • around:環繞通知(應用:十分強大,可以做任何事情)
    • 方法執行前后分別執行,可以阻止方法的執行
    • 必須手動執行目標方法
  • afterThrowing:拋出異常通知(應用:包裝異常信息)
    • 方法拋出異常后執行,如果方法沒有拋出異常,無法執行
  • after:最終通知(應用:清理現場)
    • 方法執行完畢后執行,無論方法中是否出現異常

切入點表達式

基本格式:

execution( 修飾符 返回值 包.類.方法名(參數) throws異常 )

括號中的內容其實就是聲明一個方法。通常”修飾符“和”throw 異常“省略不寫;

返回值:

基本類型,對象
*//(匹配任意返回值)

包:用限定名。可以使用通配符如:

com.abc.service//表示固定包
com.abc.crm.*.service//表示crm包下任意子包的service包
com.abc.crm..//表示crm包下面的所有子包(包括自己)
“..”可以表示自己本身和自己下面的多級包

類:可以使用固定名稱,和統配符號

*Impl //以Impl結尾
User* //以User開頭的
* //任意

方法名

addUser//固定方法
add*//以add開頭
*Do//以Do結尾

參數

()//無參
(int)//一個整型
(int,int)//兩個
(..)//參數任意

例子

execution(* *.someServiceImpl.*(..))
//所有的包下面(限定一級包)someServiceImpl類的所有任意參數的方法
execution(* *..someServiceImpl.*(..))
//所有的包下面(可以是多級包)someServiceImpl類的所有任意參數的方法
execution(* com.abc.crm.*.service..*.*(..))
//service下自己以及自己的子包的任意類的任意方法

基於xml的AspectJ編程

導入jar包

導入四個jar包

  • AspectJ的jar包
  • spring用於整合aspectJ的jar包
  • spring的AOP實現jar包
  • AOP聯盟的AOP規范jar包
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.4</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>5.2.0.RELEASE</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>

定義切面類

定義切面類用於寫對應通知的方法

public class MyAspect {
    public void before(){
        System.out.println("執行前置通知before()!");
    }
    //可以輸出當前的連接點
    public void before2(JoinPoint jp){
        System.out.println("執行前置通知before2() jp = "+ jp);
    }
    public void afterReturning(){
        System.out.println("執行后置通知afterReturning()!");
    }
    //result接收目標方法的返回結果
    //后置通知不能修改目標返回的返回結果本身
    public void afterReturning2(Object res){
        System.out.println("執行后置通知afterReturning2()目標方法的返回結果為result = "+ res +"aaa");
    }
    //環繞通知中來調用目標方法確定目標方法的執行時間
    //環繞通知可以改變目標方法的返回結果本身
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("執行環繞通知-目標方法執行之前!");
        //目標方法執行
        Object proceed = pjp.proceed();
        System.out.println("執行環繞通知-目標方法執行之后");
        if (proceed != null){
            proceed = proceed.toString().toUpperCase();
        }
        return proceed;
    }
    public void afterThrowing(){
        System.out.println("執行異常通知afterThrowing()");
    }
    public void afterThrowing2(Exception ex){
        System.out.println("執行異常通知afterThrowing2() ex = "+ex);
    }
    public void after(){
        System.out.println("執行最終同時after()");
    }
}

引入約束

引入spring對aop的約束即可

AOP配置

<!--注冊切面:交叉業務邏輯對象-->
<bean id="myAspect" class="com.abc.service.MyAspect"/>

<aop:config>
    <!--定義切入點表達式-->
    <aop:pointcut id=" " expression=""/>
    <aop:pointcut id=" " expression=""/>
    <!--配置切面-->
    <!--切面為切入點+通知-->
    <aop:aspect ref="myAspect">
    	<!--前置通知,引用切入點表達式-->
        <aop:before method=" " pointcut-ref=""/>
        <!--后置通知-->
        <aop:after-returning method=" " pointcut-ref=" " returning="res"/>
        <!--環繞通知-->
        <aop:around method=" " pointcut-ref=" "/>
        <!--異常通知-->
        <aop:after-throwing method=" " pointcut-ref=" "/>
        <!--最終通知-->
        <aop:after method=" " pointcut-ref=" "/>
</aop:config>

基於注解的AspectJ編程

  1. 導入jar包

  2. 定義切面類

  3. 引入約束

  4. 注冊AspectJ自動代理生成器

    <!--注冊aspectj的自動代理-->
    <aop:aspectj-autoproxy/>
    
  5. 在切面類中添加注解

//切面:交叉業務邏輯
@Aspect   //該類是切面類
public class MyAspect {
    @Before("doFirstPC()")
    public void before(){
        System.out.println("執行前置通知before()!");
    }
    @Before("doAllPC()")
    public void before2(JoinPoint jp){
        System.out.println("執行前置通知before2() jp = "+ jp);
    }

    @AfterReturning("doSecondPC()")
    public void afterReturning(){
        System.out.println("執行后置通知afterReturning()!");
    }
    //result接收目標方法的返回結果
    //后置通知不能修改目標返回的返回結果本身
    @AfterReturning(value = "doSecondPC()",returning = "res")
    public void afterReturning2(Object res){
        System.out.println("執行后置通知afterReturning2()目標方法的返回結果為result = "+ res +"aaa");
    }

    //環繞通知中來調用目標方法確定目標方法的執行時間
    //環繞通知可以改變目標方法的返回結果本身
    @Around("doThirdPC()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("執行環繞通知-目標方法執行之前!");
        //目標方法執行
        Object proceed = pjp.proceed();
        System.out.println("執行環繞通知-目標方法執行之后");
        if (proceed != null){
            proceed = proceed.toString().toUpperCase();
        }
        return proceed;
    }

    @AfterThrowing("doSecondPC()")
    public void afterThrowing(){
        System.out.println("執行異常通知afterThrowing()");
    }
    @AfterThrowing(value = "doSecondPC()",throwing = "ex")
    public void afterThrowing2(Exception ex){
        System.out.println("執行異常通知afterThrowing2() ex = "+ex);
    }

    @After("doSecondPC()")
    public void after(){
        System.out.println("執行最終同時after()");
    }

    @Pointcut("execution(* *..SomeServiceImpl.doFirst())")
    public void doFirstPC(){};
    @Pointcut("execution(* *..SomeServiceImpl.doSecond())")
    public void doSecondPC(){};
    @Pointcut("execution(* *..SomeServiceImpl.doThird())")
    public void doThirdPC(){};
    @Pointcut("execution(* *..SomeServiceImpl.*())")
    public void doAllPC(){};
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM