當前位置:
首頁 > 科技 > 如何使用 AOP 和自定義註解?

如何使用 AOP 和自定義註解?

作者 | 一個程序員的成長

責編 | 胡巍巍

記得今年年初剛開始面試的時候,被問的最多的就是你知道Spring的兩大核心嘛?那你說說什麼是AOP,什麼是IOC?我相信你可能也被問了很多次了。

到底是什麼是AOP?

所謂AOP也就是面向切面編程,能夠讓我們在不影響原有業務功能的前提下,橫切擴展新的功能。這裡面有一個比較顯眼的詞我們需要注意一下,橫切,它是基於橫切面對程序進行擴展的。

AOP相關術語

在Spring的AOP中有很多的術語,而且容易混淆,大家一定要先搞清楚這幾個概念:

連接點(Joinpoint):在程序執行過程中某個特定的點,比如類初始化前、類初始化後,方法調用前,方法調用後;

切點(Pointcut):所謂切點就是你所切取的類中的方法,比如你橫切的這個類中有兩個方法,那麼這兩個方法都是連接點,對這兩個方法的定位就稱之為切點;

增強(Advice):增強是織入到連接點上的一段程序,另外它還擁有連接點的相關信息;

目標對象(Target):增強邏輯的織入目標類,就是我的增強邏輯植入到什麼位置;

引介(Introduction):一種特殊的增強,它可以為類添加一些屬性喝方法;

織入(Weaving):織入就是講增強邏輯添加到目標對象的過程;

代理(Proxy):一個類被AOP織入增強後,就會產生一個結果類,他是融合了原類和增強邏輯的代理類;

切面(Aspect):切面由切點和增強組成,他是橫切邏輯定義和連接點定義的組成;

AOP功能實踐

我們這裡主要是學習SpringBoot中的一些功能,所以我們這裡用的是SpringBoot工程,版本也是最新的2.0.5版本。

創建SpringBoot工程就不說了,我們直接引入Maven的依賴:

首先我們來創建一個Controller類:

@RestController

publicclassLoginController {

@GetMapping(value ="/username")

publicStringgetLoginUserName(StringuserName, Integer age) {

returnuserName +" --- "+ age;

}

}

創建切面:

@Aspect

@Component

publicclassLogAspect{

/**

* 功能描述: 攔截對這個包下所有方法的訪問

*

* @param:[]

* @return:void

**/

@Pointcut("execution(* com.example.springbootaop.controller.*.*(..))")

publicvoidloginLog(){

}

// 前置通知

@Before("loginLog()")

publicvoidloginBefore(JoinPoint joinPoint){

// 我們從請求的上下文中獲取request,記錄請求的內容

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

HttpServletRequest request = attributes.getRequest();

System.out.println("請求路徑 : "+ request.getRequestURL());

System.out.println("請求方式 : "+ request.getMethod());

System.out.println("方法名 : "+ joinPoint.getSignature().getName());

System.out.println("類路徑 : "+ joinPoint.getSignature().getDeclaringTypeName());

System.out.println("參數 : "+ Arrays.toString(joinPoint.getArgs()));

}

@AfterReturning(returning ="object", pointcut ="loginLog()")

publicvoiddoAfterReturning(Objectobject){

System.out.println("方法的返回值 : "+object);

}

// 方法發生異常時執行該方法

@AfterThrowing(throwing ="e",pointcut ="loginLog()")

publicvoidthrowsExecute(JoinPoint joinPoint, Exception e){

System.err.println("方法執行異常 : "+ e.getMessage());

}

// 後置通知

@After("loginLog()")

publicvoidafterInform(){

System.out.println("後置通知結束");

}

// 環繞通知

@Around("loginLog()")

publicObjectsurroundInform(ProceedingJoinPoint proceedingJoinPoint){

System.out.println("環繞通知開始...");

try{

Object o = proceedingJoinPoint.proceed();

System.out.println("方法環繞proceed,結果是 :"+ o);

returno;

}catch(Throwable e) {

e.printStackTrace();

returnnull;

}

}

}

註解概述:

@Apsect:將當前類標識為一個切面;

@Pointcut:定義切點,這裡使用的是條件表達式;

@Before:前置增強,就是在目標方法執行之前執行;

@AfterReturning:後置增強,方法退出時執行;

@AfterThrowing:有異常時該方法執行;

@After:最終增強,無論什麼情況都會執行;

@Afround:環繞增強;

測試:

異常測試:

定義自定義註解

應用場景:在我之前上個項目的時候,有這樣一個註解,就是在訪問其他介面的時候必須要登錄,那麼這個時候我們就定義一個註解,讓它去對用戶是否登錄進行校驗,那麼基於這樣的一個場景,我們來定義一個校驗登錄的註解。

創建一個註解:

@Target({ElementType.METHOD,ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

public @interface Auth {

Stringdesc()default"驗證是否登錄";

}

創建一個AOP切面:

@Aspect

@Component

publicclassLoginAspect{

@Pointcut(value ="@annotation(com.example.springbootaop.annotation.Auth)")

publicvoidaccess(){

}

@Before("access()")

publicvoidbefore(){

System.out.println("開始驗證用戶是否登錄...");

}

@Around("@annotation(auth)")

publicObjectaround(ProceedingJoinPoint pj, Auth auth){

// 獲取註解中的值

System.out.println("註解中的值 : "+ auth.desc());

try{

// 檢驗是否登錄 true 已經登錄 false 未登錄

Boolean flag =false;

if(flag ==true) {

return"登錄成功";

}else{

return"未登錄";

}

}catch(Throwable throwable) {

returnnull;

}

}

}

測試未登錄:

測試登錄:

這樣我們就可以簡單的實現了一個登錄校驗的註解。

通過今天的分享你會使用AOP和自定義註解了嗎?我把源碼的地址放在下面,有興趣的朋友可以看看。

GitHub地址:

https://github.com/liangbintao/SpringBootIntegration.git

作者:一個非科班出身的屌絲男,自學半年多,找到了一份還不錯的工作,我希望做一個專註於Java領域與思維認知的公眾號,希望可以帶領更多的初學者和入門選手,通過自己努力,得到更多的技術上的提升和思維認知上的拓展。

聲明:本文為公眾號一個程序員的成長投稿,版權歸對方所有。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 CSDN 的精彩文章:

這屆 Python 程序員,很行!
拿下阿里一等獎,轉型 AI,這位技術老炮兒要說這些!

TAG:CSDN |