SpringBoot自定義注解異步記錄復雜日志詳解_第1頁
SpringBoot自定義注解異步記錄復雜日志詳解_第2頁
SpringBoot自定義注解異步記錄復雜日志詳解_第3頁
SpringBoot自定義注解異步記錄復雜日志詳解_第4頁
SpringBoot自定義注解異步記錄復雜日志詳解_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

第SpringBoot自定義注解異步記錄復雜日志詳解目錄1、背景2、技術方案-自定義注解2.1注解介紹2.2元注解2.3實現(xiàn)自定義注解3、技術方案-AOP切面3.1AOP術語解析3.2切入點表達式3.3ADVICE通知類型3.4技術實現(xiàn)3.5相關操作4、高級操作

1、背景

最近接手一個任務,需要給當前項目加一個較為復雜的日志。有多復雜呢要有日志類型、不同日志類型要有不同的操作和備注等。作為小白的我最開始的做法是在業(yè)務層寫代碼記錄日志,好處就是方便,壞處就是這種做法直接侵襲Service層,Service層無法做到職責單一了。

經(jīng)導師點撥,改用自定義注解+AOP切面異步日志

2、技術方案-自定義注解

注解(Annotation),也叫元數(shù)據(jù)。

2.1注解介紹

注解其實就是代碼里的特殊標記,這些標記可以在編譯、類加載、運行時被讀取,并執(zhí)行相應的處理。通過使用注解,程序員可以在不改變原有邏輯的情況下,在源文件中嵌入一些補充信息。

2.2元注解

元注解用于修飾其他注解的注解,在JDK5.0中提供了四種元注解:Retention、Target、Documented、Inherited

(1)Retention介紹:用于修飾注解,用于指定修飾的哪個注解的聲明周期。@Rentention包含一個RetentionPolicy枚舉類型的成員變量,使用@Rentention時必須為該value成員變量指定值

RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),編譯器直接丟棄這種策略的注釋,在.class文件中不會保留注解信息RetentionPolicy.CLASS:在class文件中有效(即class保留),保留在.class文件中,但是當運行java程序時,他就不會繼續(xù)加載了,不會保留在內(nèi)存中,JVM不會保留注解。如果注解沒有加Retention元注解,那么相當于默認的注解就是這種狀態(tài)。RetentionPolicy.RUNTIME:在運行有效(即運行時保留),當運行Java程序時,JVM會保留注釋,加載在內(nèi)存中,那么程序可以通過反射獲取該注釋。

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public@interfaceRetention{

RetentionPolicyvalue();

publicenumRetentionPolicy{

SOURCE,

CLASS,

RUNTIME

(2)Target介紹:用于修飾注解的注解,定義當前注解能夠修飾程序中的哪些元素(類、屬性、方法,構造器等等)

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public@interfaceTarget{

ElementType[]value();

(3)Documented介紹:用于指定被該元注解修飾的注解類將被javadoc工具提取成文檔。默認情況下,javadoc是不包括注解的,但是加上這個注解生成的文檔中就會帶著注解了

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public@interfaceDocumented{

(4)Inherited介紹:被它修飾的Annotation將具有繼承性。如果某個類使用了被@Inherited修飾的Annotation,則其子類將自動具有該注解。

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public@interfaceInherited{

注解的基礎知識基本介紹完畢,我們開始寫起來吧!?。?/p>

2.3實現(xiàn)自定義注解

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

public@interfaceLog{

//日志類型

LogTypelogType();

//操作類型

OperateTypeoperate();

//備注

Stringnote()default"";

3、技術方案-AOP切面

AOP切面編程一般可以幫助我們在不修改現(xiàn)有代碼的情況下,對程序的功能進行拓展,往往用于實現(xiàn)日志處理,權限控制,性能檢測,事務控制等。AOP實現(xiàn)的原理就是動態(tài)代理。在有接口的情況下,使用JDK動態(tài)代理,在沒有接口的情況下使用cglib動態(tài)代理。

3.1AOP術語解析

(1)Jointpoint:類里面那些可以被增強的方法,這些方法被稱之為連接點

(2)PointCut:實際被增強的方法,這些方法被稱之為連接點

(3)Advice:實際增加的邏輯部分稱為通知

(4)Target:被增強功能的對象(被代理的對象)

(5)Aspect:Aspect聲明類似與Java中的類聲明,在Aspect中會包含著一些PointCut以及相應的Advice.

(6)Weaving:創(chuàng)建代理對象并實現(xiàn)功能增強的聲明并運行過程將Aspect和其他對象連接起來,并創(chuàng)建Advicedobject的過程

3.2切入點表達式

切入點表達式:通過一個表達式來確定AOP要增強的是哪個或者哪些方法.

3.3ADVICE通知類型

(1)前置通知:@Before執(zhí)行前置通知,并通過JointPoint獲取方法中的參數(shù)

@Aspect

@Component

publicclassDaoAspect{

前置通知:在執(zhí)行addUser方法之前,執(zhí)行前置通知,并通過JointPoint獲取addUser()方法中的參數(shù)

@Before("execution(*com.xzit.dao.Impl.UserDaoImpl.addUser(..))")

publicvoidmethodBefore(JoinPointjoinPoint){

System.out.println("methodBeforeinvoked......");

Object[]args=joinPoint.getArgs();

System.out.println(Arrays.toString(args));

(2)后置通知:@After切點方法是否出現(xiàn)異常,后置通知都會執(zhí)行

(3)返回通知:@AfterReturning切點出現(xiàn)異常,返回通知不會執(zhí)行

(4)異常通知:@AfterThrowing切點方法出現(xiàn)異常就執(zhí)行,不出現(xiàn)異常就不執(zhí)行

(5)環(huán)繞通知:@Around在切點方法之前和之后執(zhí)行。是@Before和@AfterReturing相結合

3.4技術實現(xiàn)

根據(jù)任務背景,我選擇了返回通知@AfterReturning。使用返回通知一定要注意的是:由于我需要用到返回值,所以會用@AfterReturning注解中的returning屬性來獲取方法的返回值

returning指定的名稱必須和切面方法參數(shù)中的名稱相同。例如在下面代碼中指定的cId都是相同的

@AfterReturning(pointcut="@annotation(com.xxx.xxx.xxx.Log)",

returning="cId")

publicvoidhandleRdLogs(JoinPointjoinPoint,intcId)

切面方法參數(shù)中的參數(shù)類型必須和方法返回類型一致

@AfterReturning(pointcut="@annotation(com.xxx.xxx.xxx.Log)",

returning="cId")

publicvoidhandleRdLogs(JoinPointjoinPoint,intcId){

//獲取方法簽名

MethodSignaturemethodSignature=(MethodSignature)joinPoint.getSignature();

//獲取@Log注解內(nèi)容

if(!methodSignature.getMethod().isAnnotationPresent(Log.class)){

log.error("獲取注解@Log失敗");

thrownewException("獲取注解@Log失敗");

Loglog=methodSignature.getMethod().getAnnotation(Log.class);

//輸出日志的備注

System.out.println(log.note())

3.5相關操作

(1)獲取方法簽名

MethodSignaturemethodSignature=(MethodSignature)joinPoint.getSignature();`

(2)根據(jù)方法簽名獲取自定義注解

Loglog=methodSignature.getMethod().getAnnotation(Log.class);

(3)根據(jù)自定義注解獲取,注解內(nèi)部的參數(shù)

System.out.println(log.note())

4、高級操作

場景:不僅需要獲取返回值,還得知道方法參數(shù)的值,而且方法參數(shù)的值不能作為返回值,這個該怎么辦呢?

秀操作開始:

第一步:在注解上寫#+方法參數(shù)的名

@Log(note="#note")

publicintrdAuditReturn(Stringnote){

System.out.println(note)

xxxx.....

xxxx.....

業(yè)務代碼.....

xxxx.....

xxxx....

returncId;

第二步:實現(xiàn)切面,只要調(diào)用這個方法,就可以得到note的值了

privatefinalExpressionParserparser=newSpelExpressionParser();

privatefinalEvaluationContextevaluationContext=newStandardEvaluationContext();

privatevoidgetNote(JoinPointjoinPoint,StringBuildernoteBuilder,Stringnote)throwsNoSuchMethodException{

if(!StringUtils.isBlank(note)){

ClasstargetCls=joinPoint.getTarget().getClass();

MethodSignaturems=(MethodSignature)joinPoint.getSignature();

MethodtargetMethod=targetCls.getDeclaredMethod(ms.getName(),ms.getParameterTypes());

ParameterNameDiscovererpnd=newDefaultParameterNameDiscoverer();

String[]parameterNames=pnd.getParameterNames(targetMethod);

Object[]args=joinPoint.getArgs();

for(inti=0;iargs.length;++i){

intindex=i;

Optional.ofNullable(args[i]).ifPresent(param-{

StringparamName=parameterName

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論