首頁 > 軟體

Spring中的AOP操作你瞭解嗎

2022-02-14 19:00:31

一、AOP操作術語 

1. 連線點

類裡面哪些方法可以被增強,這些可以被增強的方法就稱為連線點。

2. 切入點

實際被真正增強的方法,稱為切入點。

3. 通知(增強)

(1)實際增強的邏輯部分稱為通知(增強)

(2)通知有如下多種型別,如下:

  • 前置通知
  • 後置通知
  • 環繞通知
  • 異常通知
  • 最終通知(finally)

4. 切面

切面是一個動作,指的是將通知應用到切入點的過程,就叫做切面。

二、AOP操作

Spring 框架一般都是基於 AspectJ 實現 AOP 操作。AspectJ 不是 Spring 組成部分,而是獨立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用,進行 AOP 操作 。

基於AspectJ實現AOP操作有如下兩種方式:

  • 基於 xml 組態檔實現 
  • 基於註解方式實現(使用) 

2.1 切入點表示式

切入點表示式作用:知道對哪個類裡面的哪個方法進行增強 ,語法結構如下所示:

execution([許可權修飾符] [返回型別] [類全路徑] [方法名稱]([參數列]) 

如下圖所示: 

編寫切點範例如下

1. 如對com.wyf.spring5.Book類中的add進行增強,則切入點表示式如下:

execution(* com.wyf.spring5.Book.add(..))

2. 如對com.wyf.spring5.Book類中所有的方法增強:

execution(* com.wyf.spring5.Book.*(..))

3. 如對 com.wyf.spring5包中的所有類,類中的所有方法都進行加強

execution(*  com.wyf.spring5.*.* (..)) 

2.2 AOP操作(AspectJ 註解方式)

 1) 首先我們建立一個類,並新增一個方法

/** * 被增強類 */public class User {    public void add(){        System.out.println("add*****");    }}/**
 * 被增強類
 */
public class User {
    public void add(){
        System.out.println("add*****");
    }
}

2)接著我們建立增強類(編寫增強邏輯) 

在增強類中建立方法,讓不同的方法代表不同的通知型別

/**
 * 增強類
 */
public class UserProxy {
    /**
     * 前置通知邏輯
     */
    public void before(){
        System.out.println("before*****");
    }
}

3)進行通知的設定

在spring組態檔中,開啟註解掃描。(採用java設定類或xml組態檔實現)

<?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.xsd                            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">    <!-- 開啟註解掃描 -->    <context:component-scan base-package="com.wyf.aopanno"></context:component-scan>    <!-- 開啟Aspect 生成代理物件 -->    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>    </beans><?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.xsd
                            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 開啟註解掃描 -->
    <context:component-scan base-package="com.wyf.aopanno"></context:component-scan>
    <!-- 開啟Aspect 生成代理物件 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
  • 使用註解建立User和UserProxy物件(類上面新增建立物件註解,此處為 @Component)
  • 在增強類上面新增註解@Aspect
/**
 * 被增強類
 */
@Component
public class User {
    public void add(){
        System.out.println("add*****");
    }
}
/**
 * 增強類
 */
@Component
@Aspect  //生成代理物件
public class UserProxy {
    /**
     * 前置通知邏輯
     */
    public void before(){
        System.out.println("before*****");
    }
}

在 spring 組態檔中開啟生成代理物件 

    <!-- 開啟Aspect 生成代理物件 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

開啟Aspect生成代理物件,相當掃描帶有@Aspect註解的類,並生成該物件的一個代理物件。

4)設定不同型別通知

在增強類的裡面,在作為通知方法上面新增通知型別註解,使用切入點表示式設定。

/**
 * 增強類
 */
@Component
@Aspect  //生成代理物件
public class UserProxy {
    /**
     * 前置通知邏輯
     */
    //@Before註解表示其作為前置通知
    //切入點表示式指定該通知為哪個類的哪個方法進行增強。
    @Before(value = "execution(* com.wyf.aopanno.User.add(..))")
    public void before(){
        System.out.println("before*****");
    }
}

測試程式碼如下:

    @Test
    public void TestAop(){
        //1. 載入spring 組態檔
        ApplicationContext context = new ClassPathXmlApplicationContext("beanAop1.xml");
        //得到物件
        User user = context.getBean("user",User.class);
        user.add();
    }

執行結果:

前文只給出了前置通知@Before的程式碼,下面給出所有5種通知的範例程式碼,對上例的所有通知情況進行補全。

/**
 * 增強類
 */
@Component
@Aspect  //生成代理物件
public class UserProxy {
    /**
     * 前置通知邏輯
     */
    //@Before註解表示其作為前置通知
    //切入點表示式指定該通知為哪個類的哪個方法進行增強。
    @Before(value = "execution(* com.wyf.aopanno.User.add(..))")
    public void before(){
        System.out.println("before*****");
    }
    /**
     * 後置通知(返回通知)
     */
    @AfterReturning(value = "execution(* com.wyf.aopanno.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning*****");
    }
    /**
     * 最終通知,有異常也會執行
     */
    @After(value = "execution(* com.wyf.aopanno.User.add(..))")
    public void after(){
        System.out.println("after*****");
    }
    /**
     * 異常通知
     */
    @AfterThrowing(value = "execution(* com.wyf.aopanno.User.add(..))")
    public void afterthrowing(){
        System.out.println("afterthrowing*****");
    }
    /**
     * 環繞通知,在方法之前和之後均通知
     */
    @Around(value = "execution(* com.wyf.aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("環繞之前*****");
        //執行被增強的方法
        proceedingJoinPoint.proceed();
        System.out.println("環繞之後*****");
    }

程式碼執行結果如下:

其中,after是在被增強方法之後執行,而afterreturning是在方法返回值之後執行。

2.3 相同切入點的抽取

在上例種,我們編寫了被增強方放的5種通知,分別為前置通知、後置通知、異常通知、最終通知以及環繞通知。我們在編寫增強類時,在通知註解中通過切入點表示式,指明瞭通知要對哪個類的哪個方法進行增強。但是,我們會發現,我們對同一方法進行增強時,其切入點表示式是相同的,為了避免重複,我們可以相同切入點進行抽取。

下例中,我們將相同切入點用@Pointcut進行了抽取,程式碼如下所示:

    //對相同切入點進行抽取
    @Pointcut(value = "execution(* com.wyf.aopanno.User.add(..))")
    public void pointdemo(){
    }

當我們在其他地方要用該切入點表示式時,直接用其方法名稱就可以。

如下所示:

@Component
@Aspect
@Order(2)
public class PersonProxy {
    //前置通知
    @Before(value = "execution(* com.wyf.aopanno.User.add(..))")
    public void before(){
        System.out.println("Person Before****");
    }
}

2.4 多個增強類對同一個方法進行增強,設定增強類優先順序 

假如我們現在又有一個增強類,其中也包含一個before()方法,也對被增強類User的add()方法進行前置增強。那麼我們如何設定其增強的順序呢?

我們通過在增強類上面新增註解 @Order(數位型別值),數位型別值越小優先順序越高 ,來保證增強的順尋,程式碼如下:

@Component
@Aspect
@Order(2)
public class PersonProxy {
    //前置通知
    @Before(value = "execution(* com.wyf.aopanno.User.add(..))")
    public void before(){
        System.out.println("Person Before****");
    }
}

三、結束

本文主要介紹了AOP關鍵子以及基於註解的AOP操作,通過一個範例,介紹了AOP的前置通知、後置通知、異常通知、最終通知以及環繞通知。

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!   


IT145.com E-mail:sddin#qq.com