一文搞懂Spring AOP的五大通知類型
一、通知類型
Advice 直譯為通知,也有人翻譯為 “增強(qiáng)處理”,共有 5 種類型,如下表所示。
| 通知類型 | 注解 | 說(shuō)明 |
|---|---|---|
| before(前置通知) | @Before | 通知方法在目標(biāo)方法調(diào)用之前執(zhí)行 |
| after(后置通知) | @After | 通知方法在目標(biāo)方法返回或異常后調(diào)用 |
| after-returning(返回通知) | @AfterReturning | 通知方法會(huì)在目標(biāo)方法返回后調(diào)用 |
| after-throwing(異常通知) | @AfterThrowing | 通知方法會(huì)在目標(biāo)方法拋出異常后調(diào)用 |
around(環(huán)繞通知) | @Around | 通知方法會(huì)將目標(biāo)方法封裝起來(lái) |
二、環(huán)境準(zhǔn)備
添加AOP依賴
在pom.xml文件里添加Spring AOP和AspectJ的jar包依賴
<dependencies>
<!--包含Spring AOP:有基本的AOP功能-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--AspectJ框架有更強(qiáng)大的AOP功能-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
創(chuàng)建目標(biāo)接口和實(shí)現(xiàn)類
/*UserDao接口*/
public interface UserDao {
public void save();
public int update();
}
/*UserDaoImpl實(shí)現(xiàn)類*/
@Repository
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("正在執(zhí)行 UserDao 的 save 方法");
}
@Override
public int update() {
System.out.println("正在執(zhí)行 UserDao 的 update 方法");
return 1;
}
}
創(chuàng)建通知類
創(chuàng)建通知類,并指定切入點(diǎn)
/*通知類*/
@Component//將這個(gè)類定義成 Bean
@Aspect//將這個(gè)Bean定義為切面
public class MyAdvice {
//指定UserDao類中的save方法為切入點(diǎn)
@Pointcut("execution(void com.bighorn.dao.UserDao.save())")
private void pt1(){}
//指定UserDao類中的update方法為切入點(diǎn)
@Pointcut("execution(int com.bighorn.dao.UserDao.update())")
private void pt2(){}
}
創(chuàng)建Spring核心配置類
/*Spring核心配置類*/
@Configuration
@ComponentScan("com.bighorn") //開(kāi)啟注解掃描
@EnableAspectJAutoProxy //開(kāi)啟 AspectJ 的自動(dòng)代理
public class SpringConfig {
}
編寫運(yùn)行程序
public class App {
public static void main(String[] args) throws SQLException {
//獲取配置類初始化容器
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
//從容器中獲取UserDao對(duì)象
UserDao userDao = context.getBean(UserDao.class);
//調(diào)用userDao的方法
userDao.save();
}
}
三、添加通知
普通通知
在MyAdvice這個(gè)通知類中添加前置通知、后置通知、返回后通知、異常后通知及相關(guān)注解。
//前置通知
@Before("pt1()")
public void before() {
System.out.println("before advice ...");
}
//后置通知
@After("pt1()")
public void after() {
System.out.println("after advice ...");
}
//返回后通知
@AfterReturning("pt1()")
public void afterReturning() {
System.out.println("afterReturning advice ...");
}
//異常后通知
@AfterThrowing("pt1()")
public void afterThrowing() {
System.out.println("afterThrowing advice ...");
}
觀察運(yùn)行App程序后的截圖,發(fā)現(xiàn)并沒(méi)有顯示異常后通知

手動(dòng)在save()方法中添加一行代碼:int i = 1/0,造成異常后再次運(yùn)行App。
發(fā)現(xiàn)異常后通知有了,但是運(yùn)行后通知卻消失了。

綜上所述: 前置通知和后置通知是一定會(huì)執(zhí)行的,而返回后通知是需要在原始方法正常執(zhí)行后才會(huì)被執(zhí)行,異常后通知是需要原始方法拋出異常才會(huì)被執(zhí)行
環(huán)繞通知(重點(diǎn))
環(huán)繞通知是非常強(qiáng)大的通知,能夠完成上述四種通知的所有功能。
/**
* 環(huán)繞通知需要攜帶ProceedingJoinPoint類型的參數(shù)
* 環(huán)繞通知類似于動(dòng)態(tài)代理的全過(guò)程:ProceedingJoinPoint類型的參數(shù)可以決定是否執(zhí)行目標(biāo)方法
* 環(huán)繞通知必須要有返回值,返回值即為目標(biāo)方法的返回值
* @param pjp
* @return Object
*/
@Around("pt2()")
public Object around(ProceedingJoinPoint pjp) {
Object result = null;
try {
System.out.println("這是環(huán)繞通知中的前置通知......");
//執(zhí)行目標(biāo)方法
result = pjp.proceed();
System.out.println("這是環(huán)繞通知中的返回通知......");
} catch (Throwable e) {
System.out.println("這是環(huán)繞通知中的異常通知......");
}
System.out.println("這是環(huán)繞通知中的后置通知......");
return result;
}
修改App類,調(diào)用UserDao的update()方法,運(yùn)行程序,觀察結(jié)果。
public class App {
public static void main(String[] args) throws SQLException {
//獲取配置類初始化容器
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
//從容器中獲取UserDao對(duì)象
UserDao userDao = context.getBean(UserDao.class);
//調(diào)用userDao的update方法
userDao.update();
}
}
運(yùn)行結(jié)果如下

注意點(diǎn)
使用環(huán)繞通知必須傳入形參ProceedingJoinPoint,并使用pjp.proceed()方法實(shí)現(xiàn)對(duì)原始方法的調(diào)用,進(jìn)而實(shí)現(xiàn)原始方法調(diào)用前后同時(shí)添加通知
通知中如果未使用使用pjp.proceed()方法實(shí)現(xiàn)對(duì)原始方法的調(diào)用,則將跳過(guò)原始方法的執(zhí)行
原始方法的返回值類型決定環(huán)繞通知的返回值類型。原始方法若不接收返回值,通知方法的返回值類型可以設(shè)置成void,也可以設(shè)置成Object;如果接收返回值,最好設(shè)定為Object類型。
由于無(wú)法預(yù)知原始方法運(yùn)行后是否會(huì)拋出異常,因此環(huán)繞通知方法必須要處理Throwable異常
以上就是一文搞懂Spring AOP的五大通知類型的詳細(xì)內(nèi)容,更多關(guān)于Spring AOP通知類型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java的動(dòng)態(tài)代理和靜態(tài)代理詳解
這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)學(xué)生成績(jī)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
PowerJob的QueryConvertUtils工作流程源碼解讀
這篇文章主要為大家介紹了PowerJob的QueryConvertUtils工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
Springboot自定義mybatis攔截器實(shí)現(xiàn)擴(kuò)展
本文主要介紹了Springboot自定義mybatis攔截器實(shí)現(xiàn)擴(kuò)展,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
rocketmq消費(fèi)負(fù)載均衡--push消費(fèi)詳解
這篇文章主要介紹了rocketmq消費(fèi)負(fù)載均衡--push消費(fèi)詳解,本文介紹了DefaultMQPushConsumerImpl消費(fèi)者,客戶端負(fù)載均衡相關(guān)知識(shí)點(diǎn)。,需要的朋友可以參考下2019-06-06
springboot?實(shí)戰(zhàn):異常與重定向問(wèn)題
這篇文章主要介紹了springboot實(shí)戰(zhàn):異常與重定向問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Java如何正確處理下載文件時(shí)HTTP頭的編碼問(wèn)題
這篇文章主要介紹了Java如何正確處理下載文件時(shí)HTTP頭的編碼問(wèn)題,2023-07-07
通常HTTP消息包括客戶機(jī)向服務(wù)器的請(qǐng)求消息和服務(wù)器向客戶機(jī)的響應(yīng)消息,今天來(lái)講解下正確處理下載文件時(shí)HTTP頭的編碼問(wèn)題,需要的朋友可以參考下
詳解使用spring cloud config來(lái)統(tǒng)一管理配置文件
這篇文章主要介紹了詳解使用spring cloud config來(lái)統(tǒng)一管理配置文件,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12

