Spring AOP有多少個通知以及它們的執(zhí)行順序介紹
更新時間:2022年11月15日 10:00:45 作者:滕青山YYDS
這篇文章主要介紹了Spring AOP有多少個通知以及它們的執(zhí)行順序,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
Spring AOP有多少個通知以及它們的執(zhí)行順序
Spring AOP有多少個通知
- ①前置通知(Before):在連接點執(zhí)行前執(zhí)行該通知
- ②正常返回通知(AfterReturning):在連接點正常執(zhí)行完后執(zhí)行該通知,若目標方法執(zhí)行異常則不會執(zhí)行該通知
- ③異常通知(AfterThrowing):在連接點執(zhí)行拋出異常時執(zhí)行該通知
- ④后置通知(after/finally):在連接點執(zhí)行完成后(不管成功、失敗、異常)都會執(zhí)行該通知
- ⑤環(huán)繞通知(Around):圍繞在連接點前后
Spring AOP通知的執(zhí)行順序
- ①環(huán)繞通知:@Around
- ②前置通知:@Before
- ③執(zhí)行連接點方法
- ④環(huán)繞通知:@Around
- ⑤后置通知:@After
- ⑥正常返回通知:@AfterReturning,如果發(fā)生異常那么就是異常通知@AfterThrowing

SpringAOP簡單案例
本文是一個老師在學校給學生上課的簡單案例,介紹了AOP的五個通知的使用,以及通知的執(zhí)行順序。通過自定義注解來充當切入點,獲取注解的類型分別對不同的老師做對應的業(yè)務處理。
代碼中的消息響應體(Result)大家可以自定義類型。
AOP的五大通知
- 前置通知:Before
- 環(huán)繞通知:Around
- 后置通知:After
- 后置返回通知:AfterReturning
- 后置異常通知:AfterThrowing
執(zhí)行順序如下圖所示:

AOP的使用方式
1.創(chuàng)建一個課題實體對象
package com.cloud.industryapi.test;
import lombok.Data;
/**
* 課題實體
* @date 2022/3/25 16:26
*/
@Data
public class ArticleEntity {
/**
* PK
*/
private Integer id;
/**
* 課題
*/
private String title;
/**
* 內容
*/
private String content;
}2.定義一個切入點,這里以自定義注解的方式實現(xiàn)
package com.cloud.industryapi.test;
import java.lang.annotation.*;
/**
* 切點標識
* @author
* @date 2022/3/25 13:09
*/
@Target({ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PointcutId {
String type() default "";
}3.聲明要織入的切面
package com.cloud.industryapi.test;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 切面
*/
@Slf4j
@Aspect
@Component
public class ArticleAspect {
/**
* 定義切入點
*/
@Pointcut("@annotation(com.cloud.industryapi.test.PointcutId)")
public void pointcut(){
}
/**
* 環(huán)繞通知
* @param joinPoint
* @param id
* @return
* @throws Throwable
*/
@Around("pointcut() && @annotation(id)")
public Object around(ProceedingJoinPoint joinPoint, PointcutId id) throws Throwable {
log.info("-------------around start-------------");
Object[] objects = joinPoint.getArgs();
switch (id.type()){
case "language":
ArticleEntity language = (ArticleEntity) objects[0];
log.info("-------------語文老師課前備課,課題:{}-------------",language.getTitle());
break;
case "mathematics":
log.info("-------------數(shù)學老師課前備課-------------");
break;
default:
throw new RuntimeException("類型非法");
}
//joinPoint.proceed()
Object s = joinPoint.proceed();
log.info("-------------叮鈴鈴鈴鈴...放學了-------------");
log.info("-------------around end-------------");
return s;
}
/**
* 前置通知
* @param joinPoint
* @param id
*/
@Before("pointcut() && @annotation(id)")
public void before(JoinPoint joinPoint,PointcutId id){
log.info("-------------before start-------------");
log.info("-------------學生進入教室,準備上課-------------");
log.info("-------------before end-------------");
}
/**
* 后置通知
* @param joinPoint
* @param id
*/
@After("pointcut() && @annotation(id)")
public void after(JoinPoint joinPoint,PointcutId id){
log.info("-------------after start-------------");
log.info("-------------學校廣播:老師們,同學們,中午好,今天學校食堂免費為你們準備了燒雞,人手一雞-------------");
log.info("-------------after end-------------");
}
/**
* 后置返回通知
* @param joinPoint
* @param id
*/
@AfterReturning("pointcut() && @annotation(id)")
public void afterReturn(JoinPoint joinPoint, PointcutId id){
log.info("-------------AfterReturning-------------");
log.info("-------------老師們同學們拿著燒雞回家了-------------");
log.info("-------------學校關閉了大門-------------");
log.info("-------------AfterReturning-------------");
}
/**
* 后置異常通知
* @param joinPoint
* @param id
*/
@AfterThrowing("pointcut() && @annotation(id)")
public void afterThrow(JoinPoint joinPoint,PointcutId id){
log.info("-------------AfterThrowing-------------");
log.info("-------------完蛋,小明同學迷路了。。。-------------");
log.info("-------------AfterThrowing-------------");
}
}注意:ProceedingJoinPoint的proceed()方法相當于前置通知和后置通知的分水嶺。
說明:ProceedingJoinPoint的proceed()方法在執(zhí)行前用來做一些
- 例如:讀取日志 ,然后執(zhí)行目標方法。ProceedingJoinPoint的proceed()方法執(zhí)行后 ,用來做一些
- 例如:寫入日志\color{#0000FF}{說明:ProceedingJoinPoint的proceed()方法在執(zhí)行前用來做一些
- 例如:讀取日志,然后執(zhí)行目標方法。ProceedingJoinPoint的proceed()方法執(zhí)行后,用來做一些
- 例如:寫入日志}說明:ProceedingJoinPoint的proceed()方法在執(zhí)行前用來做一些
- 例如:讀取日志,然后執(zhí)行目標方法。ProceedingJoinPoint的proceed()方法執(zhí)行后,用來做一些
- 例如:寫入日志
4.編寫控制器
package com.cloud.industryapi.test;
import com.cloud.common.kit.Result;
import com.cloud.common.page.FrontPagination;
import com.cloud.industry.dto.ExclusiveJumpConfigDto;
import com.cloud.industry.facede.ExclusiveJumpConfigFacede;
import com.cloud.industry.qo.ExclusiveJumpConfigQo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 文章 - 控制器
*/
@Slf4j
@RestController
@RequestMapping("/aop/test")
public class ArticleController {
/**
* 后置異常通知
*/
@PointcutId
@RequestMapping("/afterThrow")
public void afterThrow(){
log.info("-------------------進入了目標方法-------------------");
System.out.println(2/0);
}
/**
* 語文課
*
* @param ae
* @return
*/
@PointcutId(type = "language")
@PostMapping("/language")
public Result language(@RequestBody ArticleEntity ae) {
log.info("-------------目標方法開始執(zhí)行-------------");
log.info("-------------語文老師進入教室,開始講課《"+ae.getTitle()+"》-------------");
System.out.printf("%s","深藍的天空中掛著一輪金黃的圓月,下面是海邊的沙地,都種著一望無際的碧綠的西瓜。\n" +
"其間有一個十一二歲的少年,項帶銀圈,手捏一柄鋼叉,向一匹猹盡力的刺去。\n" +
"那猹卻將身一扭,反從他的胯下逃走了。\n");
log.info("-------------目標方法結束執(zhí)行-------------");
return Result.success("執(zhí)行結束");
}
/**
* 數(shù)學課
*
* @param ae
* @return
*/
@PointcutId(type = "mathematics")
@PostMapping("/mathematics")
public Result mathematics(@RequestBody ArticleEntity ae) {
log.info("-------------目標方法開始執(zhí)行-------------");
log.info("-------------數(shù)學老師進入教室-------------");
log.info("-------------“同學們,今天這節(jié)數(shù)學課,由我代上”-------------");
log.info("-------------“起立”-------------");
log.info("-------------”體~育~老~師~好~~“-------------");
log.info("-------------目標方法結束執(zhí)行-------------");
return Result.success("執(zhí)行結束");
}
}5.請求控制器

最后是請求的響應

完成
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Java利用 Exchanger 實現(xiàn)游戲中交換裝備
JDK 1.5 開始 JUC 包下提供的 Exchanger 類可用于兩個線程之間交換信息。下面我們就來看看Java是如何利用Exchanger一行代碼實現(xiàn)游戲中交換裝備的2021-09-09

