Spring AOP使用@Aspect注解 面向切面實現(xiàn)日志橫切的操作
引言:
AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預(yù)編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護的一種技術(shù).AOP是OOP的延續(xù),是軟件開發(fā)中的一個熱點,也是Spring框架中的一個重要內(nèi)容,是函數(shù)式編程的一種衍生范型。
利用AOP可以對業(yè)務(wù)邏輯的各個部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發(fā)的效率。
在Spring AOP中業(yè)務(wù)邏輯僅僅只關(guān)注業(yè)務(wù)本身,將日志記錄,性能統(tǒng)計,安全控制,事務(wù)處理,異常處理等代碼從業(yè)務(wù)邏輯代碼中劃分出來,通過對這些行為的分離,我們希望可以將它們獨立到非指導(dǎo)業(yè)務(wù)邏輯的方法中,進(jìn)而改變這些行為的時候不影響業(yè)務(wù)邏輯的代碼。
相關(guān)注解介紹如下:
@Aspect:作用是把當(dāng)前類標(biāo)識為一個切面供容器讀取
@Pointcut:Pointcut是植入Advice的觸發(fā)條件。每個Pointcut的定義包括2部分,一是表達(dá)式,二是方法簽名。方法簽名必須是 public及void型??梢詫ointcut中的方法看作是一個被Advice引用的助記符,因為表達(dá)式不直觀,因此我們可以通過方法簽名的方式為 此表達(dá)式命名。因此Pointcut中的方法只需要方法簽名,而不需要在方法體內(nèi)編寫實際代碼。
@Around:環(huán)繞增強,相當(dāng)于MethodInterceptor
@AfterReturning:后置增強,相當(dāng)于AfterReturningAdvice,方法正常退出時執(zhí)行
@Before:標(biāo)識一個前置增強方法,相當(dāng)于BeforeAdvice的功能,相似功能的還有
@AfterThrowing:異常拋出增強,相當(dāng)于ThrowsAdvice
一:引入相關(guān)依賴

二:Spring的配置文件
applicationContext.xml 中引入context、aop對應(yīng)的命名空間;配置自動掃描的包,同時使切面類中相關(guān)方法中的注解生效,需自動地為匹配到的方法所在的類生成代理對象。

創(chuàng)建簡單計算器的接口ArithmeticCalculator.java及實現(xiàn)類ArithmeticCalculatorImpl.java
package com.svse.aop;
public interface ArithmeticCalculator {
//定義四個簡單的借口 加減乘除算法
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
package com.svse.aop;
import org.springframework.stereotype.Component;
//將實現(xiàn)類加入Spring的IOC容器進(jìn)行管理
@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
現(xiàn)在想在實現(xiàn)類中的每個方法執(zhí)行前、后、以及是否發(fā)生異常等信息打印出來,需要把日志信息抽取出來,寫到對應(yīng)的切面的類中 LoggingAspect.java 中 要想把一個類變成切面類,需要兩步,
① 在類上使用 @Component 注解 把切面類加入到IOC容器中
② 在類上使用 @Aspect 注解 使之成為切面類
package com.svse.aop;
import java.util.Arrays;
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.springframework.stereotype.Component;
import com.tencentcloudapi.vod.v20180717.VodClient;
/**
* 日志切面
*
* @author zhaoshuiqing<br>
* @date 2019年6月14日 下午3:03:29
*/
@Component
@Aspect
public class LoggingAspect {
//現(xiàn)在想在實現(xiàn)類中的每個方法執(zhí)行前、后、以及是否發(fā)生異常等信息打印出來,需要把日志信息抽取出來,寫到對應(yīng)的切面的類中 LoggingAspect.java 中
//要想把一個類變成切面類,需要兩步,
//① 在類上使用 @Component 注解 把切面類加入到IOC容器中
//② 在類上使用 @Aspect 注解 使之成為切面類
/**
* 前置通知:目標(biāo)方法執(zhí)行之前執(zhí)行以下方法體的內(nèi)容
* @param jp
*/
@Before("execution(* com.svse.aop.*.*(..))")
public void beforeMethod(JoinPoint jp){
String methodName =jp.getSignature().getName();
System.out.println("【前置通知】the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
}
/**
* 返回通知:目標(biāo)方法正常執(zhí)行完畢時執(zhí)行以下代碼
* @param jp
* @param result
*/
@AfterReturning(value="execution(* com.svse.aop.*.*(..))",returning="result")
public void afterReturningMethod(JoinPoint jp, Object result){
String methodName =jp.getSignature().getName();
System.out.println("【返回通知】the method 【" + methodName + "】 ends with 【" + result + "】");
}
/**
* 后置通知:目標(biāo)方法執(zhí)行之后執(zhí)行以下方法體的內(nèi)容,不管是否發(fā)生異常。
* @param jp
*/
@After("execution(* com.svse.aop.*.*(..))")
public void afterMethod(JoinPoint jp){
System.out.println("【后置通知】this is a afterMethod advice...");
}
/**
* 異常通知:目標(biāo)方法發(fā)生異常的時候執(zhí)行以下代碼
*/
@AfterThrowing(value="execution(* com.qcc.beans.aop.*.*(..))",throwing="e")
public void afterThorwingMethod(JoinPoint jp, NullPointerException e){
String methodName = jp.getSignature().getName();
System.out.println("【異常通知】the method 【" + methodName + "】 occurs exception: " + e);
}
/**
* 環(huán)繞通知:目標(biāo)方法執(zhí)行前后分別執(zhí)行一些代碼,發(fā)生異常的時候執(zhí)行另外一些代碼
* @return
*/
/*@Around(value="execution(* com.svse.aop.*.*(..))")
public Object aroundMethod(ProceedingJoinPoint jp){
String methodName = jp.getSignature().getName();
Object result = null;
try {
System.out.println("【環(huán)繞通知中的--->前置通知】:the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
//執(zhí)行目標(biāo)方法
result = jp.proceed();
System.out.println("【環(huán)繞通知中的--->返回通知】:the method 【" + methodName + "】 ends with " + result);
} catch (Throwable e) {
System.out.println("【環(huán)繞通知中的--->異常通知】:the method 【" + methodName + "】 occurs exception " + e);
}
System.out.println("【環(huán)繞通知中的--->后置通知】:-----------------end.----------------------");
return result;
}*/
}
編寫MainTest方法進(jìn)行測試
package com.svse.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
public static void main(String[] args) {
//ClassPathXmlApplicationContext默認(rèn)是加載src目錄下的xml文件
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
ArithmeticCalculator arithmeticCalculator =(ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
System.out.println(arithmeticCalculator.getClass());
int result = arithmeticCalculator.add(3, 5);
System.out.println("result: " + result);
result = arithmeticCalculator.div(5, 0);
System.out.println("result: " + result);
}
}
運行結(jié)果:

把其它代碼都注釋掉,把環(huán)繞通知的方法釋放出來,測試結(jié)果如下:

至此AOP注解面向切面記錄日志就寫完了!
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot是如何使用SQL數(shù)據(jù)庫的?
今天給大家?guī)淼氖顷P(guān)于Springboot的相關(guān)知識,文章圍繞著SpringBoot是如何使用SQL數(shù)據(jù)庫的展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
Mybatis-plus如何通過反射實現(xiàn)動態(tài)排序不同字段功能
這篇文章主要介紹了Mybatis-plus如何通過反射實現(xiàn)動態(tài)排序不同字段功能,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02
SpringBoot如何使用MyBatisPlus逆向工程自動生成代碼
本文介紹如何使用SpringBoot、MyBatis-Plus進(jìn)行逆向工程自動生成代碼,并結(jié)合Swagger3.0實現(xiàn)API文檔的自動生成和訪問,通過詳細(xì)步驟和配置,確保Swagger與SpringBoot版本兼容,并通過配置文件和測試類實現(xiàn)代碼生成和Swagger文檔的訪問2024-12-12
Java操作數(shù)據(jù)庫(行級鎖,for update)
這篇文章主要介紹了Java操作數(shù)據(jù)庫(行級鎖,for update),文章圍繞Java操作數(shù)據(jù)庫的相關(guān)資料展開詳細(xì)內(nèi)容,需要的小伙伴可以參考一下,希望對你有所幫助2021-12-12
SpringBatch結(jié)合SpringBoot簡單使用實現(xiàn)工資發(fā)放批處理操作方式
這篇文章主要介紹了SpringBatch結(jié)合SpringBoot簡單使用實現(xiàn)工資發(fā)放批處理操作方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09

