使用Spring AOP必須添加AOP的依賴包,並配置AOPjava
<!--
只須要導入 spring-webmvc 這一個包,maven就會自動下載如下依賴包
spring-core —— Spring的核心組件
spring-beans —— SpringIoC(依賴注入)的基礎實現
spring-aop ——Spring的面向切面編程,提供AOP(面向切面編程)實現
spring-context —— Spring提供在基礎IoC功能上的擴展服務
spring-expression —— Spring表達式語言
spring-web —— SpringMVC支持WEB端應用部署架構
spring-webmvc —— REST Web服務和Web應用的視圖控制器的實現
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- aop aspect 相關jar包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
複製代碼
<!-- 激活Spring組件掃描功能,自動掃描指定包及其子包下面經過註解配置的組件 -->
<context:component-scan base-package="com.test.aop"/>
<!-- 啓動AspectJ支持proxy-target-class="true"指定spring使用cglib來生成代理方法。
不填Spring則根據條件從cglib和java動態代理中選擇 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
複製代碼
<!-- 只須要導入這個包,Maven就會下載如下依賴包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
複製代碼
因爲用的是SpringBoot,因此也不須要配置aopweb
// 匹配service類裏頭的全部方法
@Pointcut("within(com.test.service)")
public void matchType(){}
// 匹配com.test包及子包下全部類的方法
@Pointcut("within(com.test..*)"
public void matchPackage(){}
複製代碼
/**
* @annotation 匹配方法級別
* 以下,匹配 標註有 @ToExcel註解 的方法
*/
@Pointcut("@annotation(com.demo.security.ToExcel)")
public void annotation(){}
複製代碼
/**
* @within 匹配類級別
* 非 Spring環境下,要求的 annotation 的 RetentionPolicy 級別爲 CLASS
* 以下,匹配 標註有 @Service註解 的類 的全部方法
*/
@Pointcut("@within(org.springframework.stereotype.Service)")
public void within(){}
複製代碼
/**
* @target 匹配類級別
* 非 Spring環境下,要求的 annotation 的 RetentionPolicy 級別爲 RUNTIME
* 以下,匹配 標註有 @Service註解 的類 的全部方法
*/
@Pointcut("@target(org.springframework.stereotype.Service)")
public void target(){}
複製代碼
/**
* @args 匹配參數級別
* 以下,匹配 某方法的參數 所屬的類 標註有 authority註解 的方法
* 即,被攔截的方法的參數中,有的參數所屬的類 標註有 authority註解
*/
@Pointcut("@args(com.test.authority)")
public void args(){}
複製代碼
// ps:這個還沒弄清楚,就不誤人子弟了
@Pointcut("this(com.test.DemoDao)")
public void thisDemo() {}
複製代碼
// ps:這個還沒弄清楚,就不誤人子弟了
@Pointcut("target(com.test.IDao)")
public void targetDemo() {}
複製代碼
// 匹配 Spring bean 容器中,全部名稱以 Service 結尾的 bean
@Pointcut("bean(*Service)")
public void beanDemo() {}
複製代碼
//匹配任何名稱以 find 開頭並且只有一個 Long 參數的方法
@Pointcut("execution(* *..find*(Long))")
public void execution1() {
}
//匹配任何名稱以 find 開頭的並且第一個參數爲 Long 類型的方法
@Pointcut("execution(* *..find*(Long,..))")
public void execution2() {
}
複製代碼
//匹配任何 只有一個Long參數 的方法
@Pointcut("args(Long)")
public void args1() {
}
//匹配第一個參數爲 Long 類型的方法
@Pointcut("args(Long,..)")
public void args2() {
}
複製代碼
execution(<修飾符>? <返回值類型> <方法>(<參數列表>) <異常>?)spring
/**
* execution(<修飾符>? <返回值類型> <方法>(<參數列表>) <異常>?)
* 以下,
* 匹配 修飾符爲 public,
* 返回值類型爲任意類型,
* 方法爲 com.test.service包中 以Service結尾的類的因此方法,
* 參數列表爲任意參數,
* 異常爲java.lang.IllegalAccessException
* 注意,若是指定了異常,那麼只會匹配 throws 了 指定異常的方法!!!
*/
@Pointcut("execution(public * com.test.service.*Service.*(..) throws java.lang.IllegalAccessException)")
public void execution() {
}
複製代碼
做用: 定義一個切入點express
@Pointcut()註解的value參數: 一個切面表達編程
/**
* @Pointcut 註解,用於定義一個織入點
*
* 以下,
* 匹配 修飾符爲 public,
* 返回值類型爲任意類型,
* 方法爲 com.test.service包中 以Service結尾的類的因此方法,
* 參數列表爲任意參數,
* 異常爲java.lang.IllegalAccessException
*
* 的方法爲織入點
*/
@Pointcut("execution(public * com.test.service.*Service.*(..) throws java.lang.IllegalAccessException)")
public void log() {}
複製代碼
做用: 被打上 @Before 註解的方法,會在目標方法執行以前執行bash
@Before()註解的value參數: 除了是一個切面表達式以外,還能夠是一個定義好的織入點架構
/**
* @Before 註解的參數 能夠是一個切面表達式,也能夠是一個織入點
* 以下,是一個名爲log()的織入點
* 此@Before註解 將匹配log()織入點匹配到的方法
*/
@Before("log()")
public void before(){
System.out.println("此語句輸出在目標方法執行以前");
}
複製代碼
做用: 被打上 @After 註解的方法,會在目標方法執行以後執行,無論目標方法是否成功執行或拋出異常mvc
@After()註解的value參數: 除了是一個切面表達式以外,還能夠是一個定義好的織入點maven
/**
* @After 註解的參數 能夠是一個切面表達式,也能夠是一個織入點
* 以下,此@After 將匹配log()織入點 或 切面表達式匹配到的方法
*/
@After("log() || @annotation(com.demo.security.ToExcel)")
public void After(){
System.out.println("此語句輸出在目標方法執行以後");
}
複製代碼
做用: 被打上 @After 註解的方法,會將目標方法「包圍」起來, 在目標方法執行先後作一些操做spring-boot
@Around()註解的value參數: 除了是一個切面表達式以外,還能夠是一個定義好的織入點
/**
* 打上 @After 註解的方法,會將目標方法「包圍」起來,在目標方法執行先後作一些操做
* 以下,將匹配log()織入點中方法參數名爲 token 的方法
* 並將此token參數 和 ProceedingJoinPoint對象 做爲入參
*/
@Around(value = "log() && args(token)")
public Object Around(ProceedingJoinPoint joinPoint, String token) throws Throwable {
System.out.println("攔截方法的token參數值爲:" + token);
System.out.println("此語句輸出在目標方法執行以前");
try {
// 執行目標方法,並返回目標方法的執行結果
Object result = joinPoint.proceed(joinPoint.getArgs());
return result;
} catch (Throwable throwable) {
System.out.println("出現異常");
// 若是目標方法出現異常,不要`生吞`異常,最好原樣拋出
throw throwable;
} finally {
// @After註解 至關於 finally的語句,無論目標方法是否成功執行或拋出異常,都會執行
System.out.println("此語句輸出在目標方法執行以後");
}
}
複製代碼
做用: 此註解與@After註解做用同樣,不一樣之出在於它多了一個 returning參數,能夠用來獲取目標方法返回值,並做爲入參帶入方法中
@AfterReturning()註解的value參數: 除了是一個切面表達式以外,還能夠是一個定義好的織入點
/**
* 使用 returning 獲取目標方法返回值,並取名爲result,再將result做爲參數帶入方法中
*/
@AfterReturning(value = "log() || @annotation(com.demo.security.ToExcel)", returning = "result")
public void AfterReturning(Object result) {
// 打印目標方法返回結果
System.out.println(result);
System.out.println("此語句輸出在目標方法執行以後");
}
複製代碼
做用: 此註解不一樣於@After註解,它只有在目標方法拋出異常以後纔會執行
@AfterThrowing()註解的value參數: 除了是一個切面表達式以外,還能夠是一個定義好的織入點
/**
*使用 throwing 獲取目標方法拋出的異常,並取名爲e,再將 e 做爲參數帶入方法中
*/
@AfterThrowing(value="log()", throwing="e")
public void AfterThrowing(Exception e){
//處理異常
e.getMessage();
System.out.println("此方法在 目標方法拋出異常時 才執行");
}
複製代碼
首先建立一個java類,而後打上 @Aspect 和 @Component 註解,一個切面就定義好了。
package com.example.demo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 自定義切面須要在類上面打上兩個註解
*
* @Aspect註解 用於標識這個類是一個自定義切面
* @Component註解 用於將此類交給 Spring 管理
*/
@Aspect
@Component
public class Test {
/**
* @Pointcut 註解,用於定義一個織入點
* <p>
* 以下,
* 匹配 修飾符爲 public,
* 返回值類型爲任意類型,
* 方法爲 com.test.service包中 以Service結尾的類的因此方法,
* 參數列表爲任意參數,
* 異常爲java.lang.IllegalAccessException
* <p>
* 的方法爲織入點
*/
@Pointcut("execution(public * com.test.service.*Service.*(..) throws java.lang.IllegalAccessException)")
public void log() {
}
/**
* 打上 @Before 註解的方法,會在目標方法執行以前執行
*
* @Before 註解的參數 能夠是一個切面表達式,也能夠是一個織入點
* 以下,是一個名爲log()的織入點
* 此@Before註解 將匹配log()織入點匹配到的方法
*/
@Before("log()")
public void before() {
System.out.println("此語句輸出在目標方法執行以前");
}
/**
* 被打上 @After 註解的方法,會在目標方法執行以後執行,無論目標方法是否成功執行或拋出異常
*
* @After 註解的參數 能夠是一個切面表達式,也能夠是一個織入點
* 以下,此@After 將匹配log()織入點 或 切面表達式匹配到的方法
*/
@After("log() || @annotation(com.demo.security.ToExcel)")
public void After() {
System.out.println("此語句輸出在目標方法執行以後");
}
/**
* 打上 @After 註解的方法,會將目標方法「包圍」起來,在目標方法執行先後作一些操做
* 以下,將匹配log()織入點中方法參數名爲 token 的方法
* 並將此token參數 和 ProceedingJoinPoint對象 做爲入參
*/
@Around(value = "log() && args(token)")
public Object Around(ProceedingJoinPoint joinPoint, String token) throws Throwable {
System.out.println("攔截方法的token參數值爲:" + token);
System.out.println("@After此語句輸出在目標方法執行以前");
try {
// 執行目標方法,並返回目標方法的執行結果
Object result = joinPoint.proceed(joinPoint.getArgs());
return result;
} catch (Throwable throwable) {
System.out.println("出現異常");
// 若是目標方法出現異常,不要`生吞`異常,最好原樣拋出
throw throwable;
} finally {
// @After註解 至關於 finally的語句,無論目標方法是否成功執行或拋出異常,都會執行
System.out.println("此語句輸出在目標方法執行以後");
}
}
/**
* 使用 returning 獲取目標方法返回值,並取名爲result,再將result做爲參數帶入方法中
*/
@AfterReturning(value = "log() || @annotation(com.demo.security.ToExcel)", returning = "result")
public void AfterReturning(Object result) {
// 打印目標方法返回結果
System.out.println(result);
System.out.println("此語句輸出在目標方法執行以後");
}
/**
* 使用 throwing 獲取目標方法拋出的異常,並取名爲e,再將 e 做爲參數帶入方法中
*/
@AfterThrowing(value = "log()", throwing = "e")
public void AfterThrowing(Exception e) {
//處理異常
e.getMessage();
System.out.println("此方法在 目標方法拋出異常時 才執行");
}
}
複製代碼