1. 程式人生 > >spring AOP 之二:@AspectJ註解的3種配置

spring AOP 之二:@AspectJ註解的3種配置

@AspectJ相關文章

與 AspectJ 相同的是,Spring AOP 同樣需要對目標類進行增強,也就是生成新的 AOP 代理類;與 AspectJ 不同的是,Spring AOP 無需使用任何特殊命令對 Java 原始碼進行編譯,它採用執行時動態地、在記憶體中臨時生成“代理類”的方式來生成 AOP 代理。

Spring 允許使用 AspectJ Annotation 用於定義方面(Aspect)、切入點(Pointcut)和增強處理(Advice),Spring 框架則可識別並根據這些 Annotation 來生成 AOP 代理。Spring 只是使用了和 AspectJ 5 一樣的註解,但並沒有使用 AspectJ 的編譯器或者織入器(Weaver

),底層依然使用的是 Spring AOP,依然是在執行時動態生成 AOP 代理,並不依賴於 AspectJ 的編譯器或者織入器。

簡單地說,Spring 依然採用執行時生成動態代理的方式來增強目標物件,所以它不需要增加額外的編譯,也不需要 AspectJ 的織入器支援;而 AspectJ 在採用編譯時增強,所以 AspectJ 需要使用自己的編譯器來編譯 Java 檔案,還需要織入器。

為了啟用 Spring 對 @AspectJ 方面配置的支援,並保證 Spring 容器中的目標 Bean 被一個或多個方面自動增強,必須在 Spring 配置檔案中配置如下片段,

AOP的作用這裡就不再作說明了,下面開始講解一個很簡單的入門級例子。 
引用一個猴子偷桃,守護者守護果園抓住猴子的小情節。 

1、猴子偷桃類(普通類): 

package com.samter.common;  
  
/** 
 * 猴子 
 * @author Administrator 
 * 
 */  
public class Monkey {  
      
    public void stealPeaches(String name){  
        System.out.println("【猴子】"+name+"正在偷桃...");  
    }  
} 

2、守護者類(宣告為Aspect): 

package com.samter.aspect;  
  
import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; /** * 桃園守護者 * @author Administrator * */ @Aspect public class Guardian { @Pointcut("execution(* com.samter.common.Monkey.stealPeaches(..))") public void foundMonkey(){} @Before(value="foundMonkey()") public void foundBefore(){ System.out.println("【守護者】發現猴子正在進入果園..."); } @AfterReturning("foundMonkey() && args(name,..)") public void foundAfter(String name){ System.out.println("【守護者】抓住了猴子,守護者審問出了猴子的名字叫“"+name+"”..."); } }

3、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:aop="http://www.springframework.org/schema/aop"  
       xsi:schemaLocation="  
       http://www.springframework.org/schema/beans  
       http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
       http://www.springframework.org/schema/aop  
       http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"  
>  
  
    <!-- 定義Aspect -->  
    <bean id="guardian" class="com.samter.aspect.Guardian" />  
  
    <!-- 定義Common -->  
    <bean id="monkey" class="com.samter.common.Monkey" />  
  
    <!-- 啟動AspectJ支援 -->  
    <aop:aspectj-autoproxy />  
  
</beans>  

4、測試類: 

package com.samter.common;  
  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
  
public class Main {  
  
    public static void main(String[] args) {  
        ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");  
        Monkey monkey = (Monkey) context.getBean("monkey");  
        try {  
            monkey.stealPeaches("孫大聖的大徒弟");  
        }  
        catch(Exception e) {}  
    }  
  
}  

5、控制檯輸出: 

【守護者】發現猴子正在進入果園...  
【猴子】孫大聖的大徒弟正在偷桃...  
【守護者】抓住了猴子,守護者審問出了猴子的名字叫“孫大聖的大徒弟”...  

解說:

      1寫了一個猴子正在偷桃的方法。 
      2寫了一個標誌為@Aspect的類,它是守護者。它會在猴子偷桃之前發現猴子,並在猴子偷桃之後抓住猴子。 
      原理:

            A、@Aspect的宣告表示這是一個切面類。 
            B、@Pointcut使用這個方法可以將com.samter.common.Monkey.stealPeaches(..)方法宣告為poincut即切入點。作用,在stealPeaches方法被呼叫的時候執行2的foundMonkey方法。其中execution是匹配方法執行的切入點,也就是spring最常用的切入點定義方式。 
            C、@Before(value="foundMonkey()"):@Before宣告為在切入點方法執行之前執行,而後面沒有直接宣告切入點,而是value="foundMonkey()",是因為如果@afterReturning等都有所改動的時候都必須全部改動,所以統一用Pointcut的foundMonkey代替,這樣子有改動的時候僅需改動一個地方。其他@AfterReturning類同。 
      3是xml配置檔案,裡面有具體的註釋。 

特別說明:Guardian類裡面的@Pointcut("execution(* com.samter.common.Monkey.stealPeaches(..))"),如果stealPeaches有引數則..表示所有引數,@AfterReturning("foundMonkey() && args(name,..)")的&& args(name,..)可以獲取切入點方法stealPeaches的引數。 

總結:這裡列舉了一個簡單的例子,但是不難引申到應用中,當你寫一個登陸系統的時候,你或許要記錄誰成功登陸了系統,誰登陸系統密碼錯誤等等的資訊,這樣子你用切面是再合適不過的了,總之當你的事務邏輯都設計到日誌、安全檢查、事務管理等等共同的內容的時候,用切面是要比你沒有一個事務邏輯類都有相關程式碼或者相關引用好得多。 

一、@AspectJ的AOP功能的配置方式有三種:

1、通過 Spring 的 XML Schema 配置方式:

<?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"                  <!--schema方式配置-->                       
    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-2.0.xsd">

    <!-- 啟動 @AspectJ 支援 -->
    <aop:aspectj-autoproxy />  
    <bean id="horseman" class="com.dxz.aop.demo4.Horseman" />  
    <bean id="swordman" class="com.dxz.aop.demo4.Swordman" />  
    <bean class="com.dxz.aop.demo4.StorageAdvisor" />  
</beans>

當然,如果我們希望完全啟動 Spring 的“零配置”功能,則還需要啟用 Spring 的“零配置”支援,讓 Spring 自動搜尋指定路徑下 Bean 類。

所謂自動增強,指的是 Spring 會判斷一個或多個方面是否需要對指定 Bean 進行增強,並據此自動生成相應的代理,從而使得增強處理在合適的時候被呼叫。

如果不打算使用 Spring 的 XML Schema 配置方式,則應該在 Spring 配置檔案中增加如下片段來啟用 @AspectJ 支援。

2、通過<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>啟動@AspectJ(此時schema中不需要相關的AOP配置

<?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"
    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">

    <!-- 啟動@AspectJ支援 -->  
    <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
    <!-- 啟動@AspectJ支援 效果同上,若兩個同時新增即會執行兩次before方法-->  
    <!-- <aop:aspectj-autoproxy/> -->
     
    <bean id="horseman" class="com.dxz.aop.demo4.Horseman" />  
    <bean id="swordman" class="com.dxz.aop.demo4.Swordman" />  
    <bean class="com.dxz.aop.demo4.StorageAdvisor" />  
</beans>

上面配置檔案中的 AnnotationAwareAspectJAutoProxyCreator 是一個 Bean 後處理器(BeanPostProcessor),該 Bean 後處理器將會為容器中 Bean 生成 AOP 代理,當啟動了 @AspectJ 支援後,只要我們在 Spring 容器中配置一個帶 @Aspect 註釋的 Bean,Spring 將會自動識別該 Bean,並將該 Bean 作為方面 Bean 處理

在 Spring 容器中配置方面 Bean(即帶 @Aspect 註釋的 Bean),與配置普通 Bean 沒有任何區別,一樣使用 <bean.../> 元素進行配置,一樣支援使用依賴注入來配置屬性值;如果我們啟動了 Spring 的“零配置”特性,一樣可以讓 Spring 自動搜尋,並裝載指定路徑下的方面 Bean。

3、@EnableAspectJAutoProxy(@Configuration註解)spring3.1及以上版本

不用xml配置檔案的情況下,通過@Configuration來裝配Spring bean,@EnableAspectJAutoProxy來啟動spring AOP功能。見《Spring 3.1新特性之二:@Enable*註解的原始碼,spring原始碼分析之定時任務Scheduled註解

二、示例

2.1、xml schema + @AspectJ實現spring AOP(cglib)

使用 @Aspect 標註一個 Java 類,該 Java 類將會作為方面 Bean,如下面程式碼片段所示:

package com.dxz.aop.demo6;

import org.aspectj.lang.annotation.Aspect;

// 使用 @Aspect 定義一個方面類
@Aspect
public class LogAspect {
    // 定義該類的其他內容
    //...
}

方面類(用 @Aspect 修飾的類)和其他類一樣可以有方法、屬性定義,還可能包括切入點、增強處理定義。

當我們使用 @Aspect 來修飾一個 Java 類之後,Spring 將不會把該 Bean 當成元件 Bean 處理,因此負責自動增強的後處理 Bean 將會略過該 Bean,不會對該 Bean 進行任何增強處理。

開發時無須擔心使用 @Aspect 定義的方面類被增強處理,當 Spring 容器檢測到某個 Bean 類使用了 @Aspect 標註之後,Spring 容器不會對該 Bean 類進行增強。

下面將會考慮採用 Spring AOP 來改寫前面介紹的例子:

下面例子使用一個簡單的 Chinese 類來模擬業務邏輯元件:

Chinese.java

package com.dxz.aop.demo6;

import org.springframework.stereotype.Component;

@Component
public class Chinese {
    // 實現 Person 介面的 sayHello() 方法
    public String sayHello(String name) {
        String ret = name + " Hello , Spring AOP";
        System.out.println(ret);
        return ret;
    }

    // 定義一個 eat() 方法
    public void eat(String food) {
        System.out.println("我正在吃 :" + food);
    }
}

提供了上面 Chinese 類之後,接下來假設同樣需要為上面 Chinese 類的每個方法增加事務控制、日誌記錄,此時可以考慮使用 Around、AfterReturning 兩種增強處理。

先看 AfterReturning 增強處理程式碼。

AfterReturningAdviceTest.java

package com.dxz.aop.demo6;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

// 定義一個方面
@Aspect
public class AfterReturningAdviceTest {
    // 匹配 com.dxz.aop.demo6 包下所有類的下的所有方法的執行作為切入點
    @AfterReturning(returning = "rvt", pointcut = "execution(* com.dxz.aop.demo6.*.*(..))")
    public void log(Object rvt) {
        System.out.println("AfterReturningAdviceTest==獲取目標方法返回值 :" + rvt);
    }
}

上面 Aspect 類使用了 @Aspect 修飾,這樣 Spring 會將它當成一個方面 Bean 進行處理。其中程式中粗體字程式碼指定將會在呼叫 org.crazyit.app.service.impl 包下的所有類的所有方法之後織入 log(Object rvt) 方法。

再看 Around 增強處理程式碼:

package com.dxz.aop.demo6;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

// 定義一個方面
@Aspect
public class AroundAdviceTest {
    // 匹配 com.dxz.aop.demo6 包下所有類的下的所有方法的執行作為切入點
    @Around("execution(* com.dxz.aop.demo6.*.*(..))")
    public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable {
        System.out.println("AroundAdviceTest==執行目標方法之前,模擬開始事務 ...");
        // 執行目標方法,並儲存目標方法執行後的返回值
        Object rvt = jp.proceed(new String[] { "被改變的引數" });
        System.out.println("AroundAdviceTest==執行目標方法之後,模擬結束事務 ...");
        return rvt + " 新增的內容";
    }
}

與前面的 AfterReturning 增強處理類似的,此處同樣使用了 @Aspect 來修飾前面 Bean,其中粗體字程式碼指定在呼叫com.dxz.aop.demo6 包下的所有類的所有方法的“前後(Around)” 織入 processTx(ProceedingJoinPoint jp) 方法需要指出的是,雖然此處只介紹了 Spring AOP 的 AfterReturning、Around 兩種增強處理,但實際上 Spring 還支援 Before、After、AfterThrowing 等增強處理,關於 Spring AOP 程式設計更多、更細緻的程式設計細節,可以參考《輕量級 Java EE 企業應用實戰》一書。

本示例採用了 Spring 的零配置來開啟 Spring AOP,因此上面 Chinese 類使用了 @Component 修飾,而方面 Bean 則使用了 @Aspect 修飾,方面 Bean 中的 Advice 則分別使用了 @AfterReturning、@Around 修飾。接下來只要為 Spring 提供如下配置檔案即可:

applicationContext-aop6.xml

<?xml version="1.0" encoding="GBK"?>
<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-3.0.xsd 
 http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context-3.0.xsd 
 http://www.springframework.org/schema/aop 
 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <!-- 指定自動搜尋 Bean 元件、自動搜尋方面類 -->
    <context:component-scan
        base-package="com.dxz.aop.demo6">
        <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect" />
    </context:component-scan>
    <!-- 啟動 @AspectJ 支援 -->
    <aop:aspectj-autoproxy />
</beans> 

接下來按傳統方式來獲取 Spring 容器中 chinese Bean、並呼叫該 Bean 的兩個方法,程式程式碼如下:

BeanTest.java

package com.dxz.aop.demo6;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanTest {
    public static void main(String[] args) {
        // 建立 Spring 容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-aop6.xml");
        Chinese p = ctx.getBean("chinese", Chinese.class);
        System.out.println(p.sayHello("張三"));
        p.eat("西瓜");
    }
}

從上面開發過程可以看出,對於 Spring AOP 而言,開發者提供的業務元件、方面 Bean 並沒有任何特別的地方。只是方面 Bean 需要使用 @Aspect 修飾即可。程式不需要使用特別的編譯器、織入器進行處理

執行上面程式,將可以看到如下執行結果:

雖然程式是在呼叫 Chinese 物件的 sayHello、eat 兩個方法,但從上面執行結果不難看出:實際執行的絕對不是 Chinese 物件的方法,而是 AOP 代理的方法。也就是說,Spring AOP 同樣為 Chinese 類生成了 AOP 代理類。這一點可通過在程式中增加如下程式碼看出:

System.out.println(p.getClass());

上面程式碼可以輸出 p 變數所引用物件的實現類,再次執行程式將可以看到上面程式碼產生class com.dxz.aop.demo6.Chinese$$EnhancerBySpringCGLIB$$7d0b6d20的輸出,這才是 p 變數所引用的物件的實現類,這個類也就是 Spring AOP 動態生成的 AOP 代理類。從 AOP 代理類的類名可以看出,AOP 代理類是由 CGLIB 來生成的。

2.2、xml schema + @AspectJ實現spring AOP(jdk動態代理實現)

如果將上面程式程式稍作修改:只要讓上面業務邏輯類 Chinese 類實現一個任意介面——這種做法更符合 Spring 所倡導的“面向介面程式設計”的原則。假設程式為 Chinese 類提供如下 Person 介面,並讓 Chinese 類實現該介面:

Person.java

package com.dxz.aop.demo6;

public interface Person {
    String sayHello(String name);
    void eat(String food);
}

Chinese修改實現Person介面:

@Component
public class Chinese implements Person {

接下來讓 BeanTest 類面向 Person 介面、而不是 Chinese 類程式設計。即將 BeanTest 類改為如下形式:

BeanTest.java

package com.dxz.aop.demo6;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanTest {
    public static void main(String[] args) {
        // 建立 Spring 容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-aop6.xml");
        Person p = ctx.getBean("chinese", Person.class);
        System.out.println(p.sayHello("張三"));
        p.eat("西瓜");
        System.out.println(p.getClass());
    }
}

原來的程式是將面向 Chinese 類程式設計,現在將該程式改為面向 Person 介面程式設計,再次執行該程式,程式執行結果沒有發生改變。只是 System.out.println(p.getClass()); 將會輸出 class com.sun.proxy.$Proxy10,這說明此時的 AOP 代理並不是由 CGLIB 生成的,而是由 JDK 動態代理生成的

Spring AOP 框架對 AOP 代理類的處理原則是:如果目標物件的實現類實現了介面,Spring AOP 將會採用 JDK 動態代理來生成 AOP 代理類;如果目標物件的實現類沒有實現介面,Spring AOP 將會採用 CGLIB 來生成 AOP 代理類——不過這個選擇過程對開發者完全透明、開發者也無需關心。

Spring AOP 會動態選擇使用 JDK 動態代理、CGLIB 來生成 AOP 代理,如果目標類實現了介面,Spring AOP 則無需 CGLIB 的支援,直接使用 JDK 提供的 Proxy 和 InvocationHandler 來生成 AOP 代理即可。關於如何 Proxy 和 InvocationHandler 來生成動態代理不在本文介紹範圍之內,如果讀者對 Proxy 和 InvocationHandler 的用法感興趣則可自行參考 Java API 文件或《瘋狂 Java 講義》。

2.3、@[email protected]實現

在spring3.1及以上,spring可以不用xml配置裝載bean了,在@Configuration註解的環境裡,可以通過@EnableAspectJAutoProxy啟動spring AOP功能。微調上面的示例如下:

在@Aspect中

package com.dxz.aop.demo6;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration;

// 定義一個方面
@Aspect
@Configuration
public class AfterReturningAdviceTest {
    // 匹配 com.dxz.aop.demo6 包下所有類的下的所有方法的執行作為切入點
    @AfterReturning(returning = "rvt", pointcut = "execution(* com.dxz.aop.demo6.*.*(..))")
    public void log(Object rvt) {
        System.out.println("AfterReturningAdviceTest==獲取目標方法返回值 :" + rvt);
    }
}

增加spring配置類

package com.dxz.aop.demo6;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
@Import({AfterReturningAdviceTest.class})/*@Aspect可以生效,相當於Configuration類作用,都是配置類*/  
public class AppConfig {

    @Bean(name = "chinese")
    public Chinese chinese() {
        return new Chinese();
    }
}

啟動類:

package com.dxz.aop.demo6;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test6 {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Person outPut = (Person) context.getBean("chinese");
        outPut.sayHello("duan");
    }
}

結果:

資訊: Refreshing org.spring[email protected]c4437c4: startup date [Tue Dec 26 17:03:32 CST 2017]; root of context hierarchy
AfterReturningAdviceTest==獲取目標方法返回值 :[email protected]
duan Hello , Spring AOP
AfterReturningAdviceTest==獲取目標方法返回值 :duan Hello , Spring AOP

三、註解

2 註解說明

2.1 @Aspect

作用是把當前類標識為一個切面供容器讀取

2.2 @Before
標識一個前置增強方法,相當於BeforeAdvice的功能,相似功能的還有

2.3 @AfterReturning

後置增強,相當於AfterReturningAdvice,方法正常退出時執行

2.4 @AfterThrowing

異常丟擲增強,相當於ThrowsAdvice

2.5 @After

final增強,不管是丟擲異常或者正常退出都會執行

2.6 @Around

環繞增強,相當於MethodInterceptor

2.7 @DeclareParents

引介增強,相當於IntroductionInterceptor

3 execution切點函式

execution函式用於匹配方法執行的連線點,語法為:

execution(方法修飾符(可選)  返回型別  方法名  引數  異常模式(可選)) 

引數部分允許使用萬用字元:

*  匹配任意字元,但只能匹配一個元素

.. 匹配任意字元,可以匹配任意多個元素,表示類時,必須和*聯合使用

+  必須跟在類名後面,如Horseman+,表示類本身和繼承或擴充套件指定類的所有類

示例中的* chop(..)解讀為:

方法修飾符  無

返回型別      *匹配任意數量字元,表示返回型別不限

方法名          chop表示匹配名稱為chop的方法

引數               (..)表示匹配任意數量和型別的輸入引數

異常模式       不限

更多示例:

void chop(String,int)

匹配目標類任意修飾符方法、返回void、方法名chop、帶有一個String和一個int型引數的方法

public void chop(*)

匹配目標類public修飾、返回void、方法名chop、帶有一個任意型別引數的方法

public String *o*(..)

 匹配目標類public修飾、返回String型別、方法名中帶有一個o字元、帶有任意數量任意型別引數的方法

public void *o*(String,..)

 匹配目標類public修飾、返回void、方法名中帶有一個o字元、帶有任意數量任意型別引數,但第一個引數必須有且為String型的方法

也可以指定類:

public void examples.chap03.Horseman.*(..)

匹配Horseman的public修飾、返回void、不限方法名、帶有任意數量任意型別引數的方法

public void examples.chap03.*man.*(..)

匹配以man結尾的類中public修飾、返回void、不限方法名、帶有任意數量任意型別引數的方法

指定包:

public void examples.chap03.*.chop(..)

匹配examples.chap03包下所有類中public修飾、返回void、方法名chop、帶有任意數量任意型別引數的方法

public void examples..*.chop(..)

匹配examples.包下和所有子包中的類中public修飾、返回void、方法名chop、帶有任意數量任意型別引數的方法
可以用這些表示式替換StorageAdvisor中的程式碼並觀察效果

4 更多切點函式

除了execution(),Spring中還支援其他多個函式,這裡列出名稱和簡單介紹,以方便根據需要進行更詳細的查詢

4.1 @annotation()

表示標註了指定註解的目標類方法

例如 @annotation(org.springframework.transaction.annotation.Transactional) 表示標註了@Transactional的方法

4.2 args()

通過目標類方法的引數型別指定切點

例如 args(String) 表示有且僅有一個String型引數的方法

4.3 @args()

通過目標類引數的物件型別是否標註了指定註解指定切點

如 @args(org.springframework.stereotype.Service) 表示有且僅有一個標註了@Service的類引數的方法

4.4 within()

通過類名指定切點

如 with(examples.chap03.Horseman) 表示Horseman的所有方法

4.5 target()

通過類名指定,同時包含所有子類

如 target(examples.chap03.Horseman)  且Elephantman extends Horseman,則兩個類的所有方法都匹配

4.6 @within()

匹配標註了指定註解的類及其所有子類

如 @within(org.springframework.stereotype.Service) 給Horseman加上@Service標註,則Horseman和Elephantman 的所有方法都匹配

4.7 @target()

所有標註了指定註解的類

如 @target(org.springframework.stereotype.Service) 表示所有標註了@Service的類的所有方法

4.8 this()

大部分時候和target()相同,區別是this是在執行時生成代理類後,才判斷代理類與指定的物件型別是否匹配

5 邏輯運算子

表示式可由多個切點函式通過邏輯運算組成

5.1 &&

與操作,求交集,也可以寫成and

例如 execution(* chop(..)) && target(Horseman)  表示Horseman及其子類的chop方法

5.2 ||

或操作,求並集,也可以寫成or

例如 execution(* chop(..)) || args(String)  表示名稱為chop的方法或者有一個String型引數的方法

5.3 !

非操作,求反集,也可以寫成not

例如 execution(* chop(..)) and !args(String)  表示名稱為chop的方法但是不能是隻有一個String型引數的方法

相關推薦

spring AOP @AspectJ註解3配置

@AspectJ相關文章 與 AspectJ 相同的是,Spring AOP 同樣需要對目標類進行增強,也就是生成新的 AOP 代理類;與 AspectJ 不同的是,Spring AOP 無需使用任何特殊命令對 Java 原始碼進行編譯,它採用執行時動態地、在記憶體中臨時生成“代理類”的方式

spring AOP @AspectJ切入點識別符號語法詳解

@AspectJ相關文章   Spring AOP支援的AspectJ切入點指示符(用來指示切入點表示式目的),在Spring AOP中目前只有執行方法這一個連線點(因為Spring基於動態代理,所以Spring只支援方法連線點。這與一些其他的AOP框架是不同的,例如AspectJ和JBoss,

Spring 3.1新特性@Enable*註解的原始碼,spring原始碼分析定時任務Scheduled註解

分析SpringBoot的自動化配置原理的時候,可以觀察下這些@Enable*註解的原始碼,可以發現所有的註解都有一個@Import註解。@Import註解是用來匯入配置類的,這也就是說這些自動開啟的實現其實是匯入了一些自動配置的Bean。 如:freemarker的自動化配置類FreeMarkerAuto

spring AOP 使用@AspectJ定義切入點

@AspectJ相關文章 使用註解來建立切面是AspectJ 5所引入的關鍵特性。AspectJ 5之前,編寫AspectJ切面需要學 習一種Java語言的擴充套件,但是AspectJ面向註解的模型可以非常簡便地通過少量註解把任意類 轉變為切面。 AspectJ提供了五個註解來定義通知,如表4

深入理解Spring AOP代理對象生成

gets code 網上 none work class als post 產生 深入理解Spring AOP之二代理對象生成 spring代理對象 上一篇博客中講到了Spring的一些基本概念和初步講了實現方

使用Spring框架入門基於註解+XML配置的IOC/DI的使用

bsp hot sources hierarchy osi pan ioc clas operate 一、簡述 本文主要講使用註解+xml配合使用的幾種使用方式。基礎課程請看前一節。 二、步驟 1、為Pom.xml中引入依賴:本例中使用的是spring-context

SpringSecurity學習筆記SpringSecurity結構及基本配置

Spring Security3.2分為11個模組,如下表所示: Spring Security3.2引入了新的Java配置方案,完全不在需要通過XML來配置安全性功能。如下,展現了Spring Security最簡單的Java配置: @EnableWebSecurity

Redis系列Redis的安裝與配置

Redis在linux和windows下都能使用,但是Redis本身並沒有windows版本,平時使用的windows版Redis都是Microsoft的團隊在github上維護了的一個Redis分支,用於支援Redis在windows上的使用。所以,windo

基礎總結篇Activity的四launchMode

合抱之木,生於毫末;九層之臺,起於累土;千里之行,始於足下。《老子》 今天在社群看到有朋友問“如何在半年內成為頂級架構師”,有網友道“關燈睡覺,不用半年的...”,的確,做夢還來的快一些。作為一個程式設計師,樹立遠大的目標是值得欣賞的,但不能只去空想,要一步一步地實踐

Spring Ioc -依賴注入的幾方式

一 setter方法注入 上一篇中Spring版HelloWorld中,helloaction注入helloservice是採用了setter方法。 配置檔案如下: action實現類中程式碼: private IHelloService helloservice;

spring-AOP)實現原理AspectJ註解方式

在上一篇spring-AOP(一)實現原理我們瞭解瞭如何使用ProxyFactory來建立AOP代理物件,但其過程需要實現一些介面,並且需要一些比較複雜的配置。因此,在spring2.0之後,提供了一種較為便利的方式。 使用@Aspect註解宣告一個切面類,之後通過@EnableAspectJAutoProx

Spring AOPAspectJ註解方式使用

需要匯入的jar包,請看上一篇部落格。 註解: 如果使用註解進行aop開發,必須進行aspectj自動代理 <aop:aspectj-autoproxy> 通知註解 @Before 前置 @AfterReturning 後置

10、SSM框架-Spring AOP基於註解的宣告式AspectJ(10)

spring除了支援Schema方式配置AOP,還支援註解方式:使用@AspectJ風格的切面宣告。匯入需要的包:aspectjweaver.jar、aopalliance-1.0.jar 一、基本使用方法  1.1、啟用對@AspectJ的支援        Sprin

Spring AOP AspectJ註解和XML配置實現(Maven構建)

xml配置 1.介面和實現類 public interface UserManager { public String findUserById(int userId); } @Service public class UserManage

SSM框架專案搭建系列(七)—Spring AOP基於註解的宣告式AspectJ

工程結構 其中AOP和com.ssm包下面的檔案不用管;dispatcher-servlet.xml和web.xml和之前專案中的內容一樣。 applicationContext.xml <?xml version="1.0" encodin

Spring入門()— IOC註解Spring測試AOP入門

兩種 cts his 工作 source print 編程 實現機制 工廠 一、Spring整合Servlet背後的細節 1. 為什麽要在web.xml中配置listener <listener> <listener-class>org.s

Https系列https的SSL證書在服務器端的部署,基於tomcat,spring boot

onf 基於 分享 height 轉化 自簽名 size class ont 一:本文的主要內容介紹 CA證書的下載及相應文件的介紹 CA證書在tomcat的部署 CA證書在spring boot的部署 自簽名證書的部署 二:一些內容的回顧 在Https系列之一中已介

自定義spring boot starter三部曲實戰開發

本文是《自定義spring boot starter三部曲》的第二篇,上一篇中我們通過學習spring cloud的starter,對spring boot的starter有了初步瞭解,也設計好了實戰內容,今天就來一起實現; 三部曲文章連結 《自定義spring boot

Spring Boot 系統Spring Boot 修改預設埠號和context path

上一篇檔案我們通過一個例項進行了spring boot 入門,我們發現tomcat埠號和上下文(context path)都是預設的,如果我們對於這兩個值有特殊需要的話,需要自己制定的時候怎麼辦呢? 一、解決辦法 1、編寫application.properties,用來重寫Spring B

java基礎(五)spring aop @aspect

Aspectj切入點語法定義 例如定義切入點表示式 execution(* com.sample.service.impl….(…)) 一:execution()是最常用的切點函式,其語法如下所示: pointcut 宣告"切入點", 整個表示式可以分為五個部分