天天看點

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

目錄

  • 一、基于XML配置的Spring AOP
  • 二、使用注解配置AOP
  • 三、AspectJ切點函數
  • 四、AspectJ通知注解
  • 五、零配置實作Spring IoC與AOP
  • 六、示例下載下傳

AOP(Aspect Oriented Programming)面向切面程式設計,通過預編譯方式和運作期動态代理實作程式功能的橫向多子產品統一控制的一種技術。AOP是OOP的補充,是Spring架構中的一個重要内容。利用AOP可以對業務邏輯的各個部分進行隔離,進而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。AOP可以分為靜态織入與動态織入,靜态織入即在編譯前将需織入内容寫入目标子產品中,這樣成本非常高。動态織入則不需要改變目标子產品。Spring架構實作了AOP,使用注解配置完成AOP比使用XML配置要更加友善與直覺。上一篇随筆中已經詳細講了代理模式。

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

一、基于XML配置的Spring AOP

在講注解實作AOP功能前先用前面學習過的使用xml配置Spring AOP功能,這樣是為了對比以便更好的了解。

1.1、建立一個Maven項目,添加引用,項目的pom.xml檔案如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.zhangguo</groupId>
  <artifactId>Spring052</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>Spring052</name>
  <url>http://maven.apache.org</url>

  <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.3.0.RELEASE</spring.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
            <version>4.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.4</version>
        </dependency>
    </dependencies>
</project>      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

1.2、建立要被代理的Math類,代碼如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop01;

/**
 * 被代理的目标類
 */
public class Math{
    //加
    public int add(int n1,int n2){
        int result=n1+n2;
        System.out.println(n1+"+"+n2+"="+result);
        return result;
    }
    
    //減
    public int sub(int n1,int n2){
        int result=n1-n2;
        System.out.println(n1+"-"+n2+"="+result);
        return result;
    }
    
    //乘
    public int mut(int n1,int n2){
        int result=n1*n2;
        System.out.println(n1+"X"+n2+"="+result);
        return result;
    }
    
    //除
    public int div(int n1,int n2){
        int result=n1/n2;
        System.out.println(n1+"/"+n2+"="+result);
        return result;
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

1.3、編輯AOP中需要使用到的通知類Advices.java代碼如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop01;

import org.aspectj.lang.JoinPoint;

/**
 * 通知類,橫切邏輯
 *
 */
public class Advices {
    
    public void before(JoinPoint jp){
        System.out.println("----------前置通知----------");
        System.out.println(jp.getSignature().getName());
    }
    
    public void after(JoinPoint jp){
        System.out.println("----------最終通知----------");
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

1.4、配置容器初始化時需要的XML檔案,aop01.xml檔案内容如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與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:p="http://www.springframework.org/schema/p"
    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/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
       
    <!-- 被代理對象 -->
    <bean id="math" class="com.zhangguo.Spring052.aop01.Math"></bean>
    
    <!-- 通知 -->
    <bean id="advices" class="com.zhangguo.Spring052.aop01.Advices"></bean>
    
    <!-- aop配置 -->
    <aop:config proxy-target-class="true">
        <!--切面 -->
        <aop:aspect ref="advices">
            <!-- 切點 -->
            <aop:pointcut expression="execution(* com.zhangguo.Spring052.aop01.Math.*(..))" id="pointcut1"/>
            <!--連接配接通知方法與切點 -->
            <aop:before method="before" pointcut-ref="pointcut1"/>
            <aop:after method="after" pointcut-ref="pointcut1"/>
        </aop:aspect>
    </aop:config>

</beans>      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

1.5、測試代碼Test.java如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop01;

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

public class Test {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("aop01.xml");
        Math math = ctx.getBean("math", Math.class);
        int n1 = 100, n2 = 5;
        math.add(n1, n2);
        math.sub(n1, n2);
        math.mut(n1, n2);
        math.div(n1, n2);
    }

}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

運作結果:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

二、使用注解配置AOP

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

2.1、在上一個示例中修改被代理的類Math,為了實作IOC掃描在Math類上注解了@Service并命名bean為math。相當于上一個示例中在xml配置檔案中增加了一個bean,<!-- 被代理對象 --><bean id="math" class="com.zhangguo.Spring052.aop01.Math"></bean>,Math類的代碼如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop02;

import org.springframework.stereotype.Service;

/**
 * 被代理的目标類
 */
@Service("math")
public class Math{
    //加
    public int add(int n1,int n2){
        int result=n1+n2;
        System.out.println(n1+"+"+n2+"="+result);
        return result;
    }
    
    //減
    public int sub(int n1,int n2){
        int result=n1-n2;
        System.out.println(n1+"-"+n2+"="+result);
        return result;
    }
    
    //乘
    public int mut(int n1,int n2){
        int result=n1*n2;
        System.out.println(n1+"X"+n2+"="+result);
        return result;
    }
    
    //除
    public int div(int n1,int n2){
        int result=n1/n2;
        System.out.println(n1+"/"+n2+"="+result);
        return result;
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

 2.2、修改通知類Advices,代碼中有3個注解,@Component表示該類的執行個體會被Spring IOC容器管理;@Aspect表示聲明一個切面;@Before表示before為前置通知,通過參數execution聲明一個切點,Advices.java代碼如下所示:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop02;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * 通知類,橫切邏輯
 *
 */
@Component
@Aspect
public class Advices {
    @Before("execution(* com.zhangguo.Spring052.aop02.Math.*(..))")
    public void before(JoinPoint jp){
        System.out.println("----------前置通知----------");
        System.out.println(jp.getSignature().getName());
    }
    
    @After("execution(* com.zhangguo.Spring052.aop02.Math.*(..))")
    public void after(JoinPoint jp){
        System.out.println("----------最終通知----------");
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

 上面的代碼與下面的配置基本等同

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
<!-- 通知 -->
    <bean id="advices" class="com.zhangguo.Spring052.aop01.Advices"></bean>
    
    <!-- aop配置 -->
    <aop:config proxy-target-class="true">
        <!--切面 -->
        <aop:aspect ref="advices">
            <!-- 切點 -->
            <aop:pointcut expression="execution(* com.zhangguo.Spring052.aop01.Math.*(..))" id="pointcut1"/>
            <!--連接配接通知方法與切點 -->
            <aop:before method="before" pointcut-ref="pointcut1"/>
            <aop:after method="after" pointcut-ref="pointcut1"/>
        </aop:aspect>
    </aop:config>      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

2.3、新增配置檔案aop02.xml,在配置IOC的基礎上增加了aop:aspectj-autoproxy節點,Spring架構會自動為與AspectJ切面配置的Bean建立代理,proxy-target-class="true"屬性表示被代理的目标對象是一個類,而非實作了接口的類,主要是為了選擇不同的代理方式。

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與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:p="http://www.springframework.org/schema/p"
    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/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="com.zhangguo.Spring052.aop02">
        </context:component-scan>
        <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

2.4、測試運作代碼Test.java如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop02;

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

public class Test {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("aop02.xml");
        Math math = ctx.getBean("math", Math.class);
        int n1 = 100, n2 = 5;
        math.add(n1, n2);
        math.sub(n1, n2);
        math.mut(n1, n2);
        math.div(n1, n2);
    }

}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

運作結果:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

三、AspectJ切點函數

切點函數可以定位到準确的橫切邏輯位置,在前面的示例中我們隻使用過execution(* com.zhangguo.Spring052.aop02.Math.*(..)),execution就是一個切點函數,但該函數隻什麼方法一級,如果我們要織入的範圍是類或某個注解則execution就不那麼好用了,其實一共有9個切點函數,有不同的針對性。

@AspectJ使用AspectJ專門的切點表達式描述切面,Spring所支援的AspectJ表達式可分為四類:

方法切點函數:通過描述目标類方法資訊定義連接配接點。

方法參數切點函數:通過描述目标類方法入參資訊定義連接配接點。

目标類切點函數:通過描述目标類類型資訊定義連接配接點。

代理類切點函數:通過描述代理類資訊定義連接配接點。

常見的AspectJ表達式函數:

execution():滿足比對模式字元串的所有目标類方法的連接配接點

@annotation():任何标注了指定注解的目标方法連結點

args():目标類方法運作時參數的類型指定連接配接點

@args():目标類方法參數中是否有指定特定注解的連接配接點

within():比對指定的包的所有連接配接點

target():比對指定目标類的所有方法

@within():比對目标對象擁有指定注解的類的所有方法

@target():比對目前目标對象類型的執行方法,其中目标對象持有指定的注解

this():比對目前AOP代理對象類型的所有執行方法

最常用的是:execution(<修飾符模式>?<傳回類型模式><方法名模式>(<參數模式>)<異常模式>?)切點函數,可以滿足多數需求。

為了展示各切點函數的功能現在新增一個類StrUtil,類如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop03;

import org.springframework.stereotype.Component;

@Component("strUtil")
public class StrUtil {
    public void show(){
        System.out.println("Hello StrUtil!");
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

測試代碼如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop03;

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

public class Test {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("aop03.xml");
        IMath math = ctx.getBean("math", Math.class);
        int n1 = 100, n2 = 5;
        math.add(n1, n2);
        math.sub(n1, n2);
        math.mut(n1, n2);
        math.div(n1, n2);
        
        StrUtil strUtil=ctx.getBean("strUtil",StrUtil.class);
        strUtil.show();
    }

}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

3.1、切點函數execution,通知與切面的定義如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop03;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * 通知類,橫切邏輯
 *
 */
@Component
@Aspect
public class Advices {
    @Before("execution(* com.zhangguo.Spring052.aop03.Math.*(..))")
    public void before(JoinPoint jp){
        System.out.println("----------前置通知----------");
        System.out.println(jp.getSignature().getName());
    }
    
    //execution切點函數
    //com.zhangguo.Spring052.aop03包下所有類的所有方法被切入
    @After("execution(* com.zhangguo.Spring052.aop03.*.*(..))")
    public void after(JoinPoint jp){
        System.out.println("----------最終通知----------");
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

運作結果如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

execution(<修飾符模式>?<傳回類型模式><方法名模式>(<參數模式>)<異常模式>?)

3.2、切點函數within

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
//within切點函數
    //com.zhangguo.Spring052.aop03包下所有類的所有方法被切入
    @After("within(com.zhangguo.Spring052.aop03.*)")
    public void after(JoinPoint jp){
        System.out.println("----------最終通知----------");
    }      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

3.3、this切點函數

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
//this切點函數
    //實作了IMath接口的代理對象的任意連接配接點
    @After("this(com.zhangguo.Spring052.aop03.IMath)")
    public void after(JoinPoint jp){
        System.out.println("----------最終通知----------");
    }      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

3.4、args切點函數

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
//args切點函數
    //要求方法有兩個int類型的參考才會被織入橫切邏輯
    @After("args(int,int)")
    public void after(JoinPoint jp){
        System.out.println("----------最終通知----------");
    }      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

如果參數類型不是基本資料類型則需要包名。

3.5、@annotation切點函數

先自定義一個可以注解在方法上的注解

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop03;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnno {
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
//@annotation切點函數
    //要求方法必須被注解com.zhangguo.Spring052.aop03.MyAnno才會被織入橫切邏輯
    @After("@annotation(com.zhangguo.Spring052.aop03.MyAnno)")
    public void after(JoinPoint jp){
        System.out.println("----------最終通知----------");
    }      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop03;

import org.springframework.stereotype.Component;

@Component("strUtil")
public class StrUtil {
    @MyAnno
    public void show(){
        System.out.println("Hello StrUtil!");
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

運作結果:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

其它帶@的切點函數都是針對注解的

四、AspectJ通知注解

AspectJ通知注解共有6個,常用5個,引介少用一些。

先解決定義切點複用的問題,如下代碼所示,切點函數的内容完全一樣:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop04;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * 通知類,橫切邏輯
 *
 */
@Component
@Aspect
public class Advices {
    @Before("execution(* com.zhangguo.Spring052.aop04.Math.*(..))")
    public void before(JoinPoint jp){
        System.out.println("----------前置通知----------");
        System.out.println(jp.getSignature().getName());
    }
    
    @After("execution(* com.zhangguo.Spring052.aop04.Math.*(..))")
    public void after(JoinPoint jp){
        System.out.println("----------最終通知----------");
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

可以先定義一個切點然後複用,如下所示:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop04;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * 通知類,橫切邏輯
 */
@Component
@Aspect
public class Advices {
    //切點
    @Pointcut("execution(* com.zhangguo.Spring052.aop04.Math.*(..))")
    public void pointcut(){
    }
    
    @Before("pointcut()")
    public void before(JoinPoint jp){
        System.out.println("----------前置通知----------");
        System.out.println(jp.getSignature().getName());
    }
    
    @After("pointcut()")
    public void after(JoinPoint jp){
        System.out.println("----------最終通知----------");
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

修改Advices.java檔案,增加各種通知類型如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop04;

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.stereotype.Component;

/**
 * 通知類,橫切邏輯
 */
@Component
@Aspect
public class Advices {
    //切點
    @Pointcut("execution(* com.zhangguo.Spring052.aop04.Math.a*(..))")
    public void pointcut(){
    }
    
    //前置通知
    @Before("pointcut()")
    public void before(JoinPoint jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("----------前置通知----------");
    }
    
    //最終通知
    @After("pointcut()")
    public void after(JoinPoint jp){
        System.out.println("----------最終通知----------");
    }
    
    //環繞通知
    @Around("execution(* com.zhangguo.Spring052.aop04.Math.s*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println(pjp.getSignature().getName());
        System.out.println("----------環繞前置----------");
        Object result=pjp.proceed();
        System.out.println("----------環繞後置----------");
        return result;
    }
    
    //傳回結果通知
    @AfterReturning(pointcut="execution(* com.zhangguo.Spring052.aop04.Math.m*(..))",returning="result")
    public void afterReturning(JoinPoint jp,Object result){
        System.out.println(jp.getSignature().getName());
        System.out.println("結果是:"+result);
        System.out.println("----------傳回結果----------");
    }
    
    //異常後通知
    @AfterThrowing(pointcut="execution(* com.zhangguo.Spring052.aop04.Math.d*(..))",throwing="exp")
    public void afterThrowing(JoinPoint jp,Exception exp){
        System.out.println(jp.getSignature().getName());
        System.out.println("異常消息:"+exp.getMessage());
        System.out.println("----------異常通知----------");
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

運作結果:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

五、零配置實作Spring IoC與AOP

為了實作零配置在原有示例的基礎上我們新增一個類User,如下所示:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop05;

public class User {
    public void show(){
        System.out.println("一個使用者對象");
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

該類并未注解,容器不會自動管理。因為沒有xml配置檔案,則使用一個作為配置資訊,ApplicationCfg.java檔案如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop05;

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

@Configuration  //用于表示目前類為容器的配置類,類似<beans/>
@ComponentScan(basePackages="com.zhangguo.Spring052.aop05")  //掃描的範圍,相當于xml配置的結點<context:component-scan/>
@EnableAspectJAutoProxy(proxyTargetClass=true)  //自動代理,相當于<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
public class ApplicationCfg {
    //在配置中聲明一個bean,相當于<bean id=getUser class="com.zhangguo.Spring052.aop05.User"/>
    @Bean
    public User getUser(){
        return new User();
    }
}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

該類的每一部分内容基本都與xml 配置有一對一的關系,請看注釋,這樣做要比寫xml友善,但不便釋出後修改。測試代碼如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳
package com.zhangguo.Spring052.aop05;

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

public class Test {

    public static void main(String[] args) {
        // 通過類初始化容器
        ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationCfg.class);
        Math math = ctx.getBean("math", Math.class);
        int n1 = 100, n2 = 0;
        math.add(n1, n2);
        math.sub(n1, n2);
        math.mut(n1, n2);
        try {
            math.div(n1, n2);
        } catch (Exception e) {
        }
        
        User user=ctx.getBean("getUser",User.class);
        user.show();
    }

}      
Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

 advices.java 同上,沒有任何變化,運作結果如下:

Spring架構學習(九)——Spring實作AOP的多種方式 一、基于XML配置的Spring AOP 二、使用注解配置AOP 三、AspectJ切點函數 四、AspectJ通知注解 五、零配置實作Spring IoC與AOP 六、示例下載下傳

六、示例下載下傳

點選下載下傳