<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
最近接手一個任務,需要給當前專案加一個較為複雜的紀錄檔。有多複雜呢? 要有紀錄檔型別、不同紀錄檔型別要有不同的操作和備註等。作為小白的我最開始的做法是在業務層寫程式碼記錄紀錄檔,好處就是方便,壞處就是這種做法直接侵襲Service層,Service層無法做到職責單一了。
經導師點撥,改用自定義註解+AOP切面非同步紀錄檔
註解(Annotation),也叫後設資料。
註解其實就是程式碼裡的特殊標記,這些標記可以在編譯、類載入、執行時被讀取,並執行相應的處理。通過使用註解,程式設計師可以在不改變原有邏輯的情況下,在原始檔中嵌入一些補充資訊。
元註解用於修飾其他註解的註解,在JDK5.0中提供了四種元註解:Retention、Target、Documented、Inherited
(1) Retention介紹: 用於修飾註解,用於指定修飾的哪個註解的宣告週期。@Rentention包含一個RetentionPolicy列舉型別的成員變數,使用@Rentention時必須為該value成員變數指定值
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); } public enum RetentionPolicy { SOURCE, CLASS, RUNTIME }
(2)Target 介紹: 用於修飾註解的註解,定義當前註解能夠修飾程式中的哪些元素(類、屬性、方法,構造器等等)
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
(3)Documented 介紹: 用於指定被該元註解修飾的註解類將被javadoc工具提取成檔案。預設情況下,javadoc是不包括註解的,但是加上這個註解生成的檔案中就會帶著註解了
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }
(4)Inherited 介紹:被它修飾的Annotation將具有繼承性。如果某個類使用了被@Inherited修飾的Annotation,則其子類將自動具有該註解。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }
註解的基礎知識基本介紹完畢,我們開始寫起來吧!!!
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface Log { // 紀錄檔型別 LogType logType() ; // 操作型別 OperateType operate(); // 備註 String note() default ""; }
AOP切面程式設計一般可以幫助我們在不修改現有程式碼的情況下,對程式的功能進行拓展, 往往用於實現 紀錄檔處理,許可權控制,效能檢測,事務控制等。AOP實現的原理就是動態代理。在有介面的情況下,使用JDK動態代理,在沒有介面的情況下使用cglib動態代理。
(1) Joint point:類裡面那些可以被增強的方法,這些方法被稱之為連線點
(2) PointCut:實際被增強的方法,這些方法被稱之為連線點
(3) Advice:實際增加的邏輯部分稱為通知
(4) Target:被增強功能的物件(被代理的物件)
(5) Aspect:Aspect 宣告類似與Java中的類宣告,在Aspect中會包含著一些PointCut以及相應的Advice.
(6) Weaving:建立代理物件並實現功能增強的宣告並執行過程將Aspect和其他物件連線起來,並建立Adviced object的過程
切入點表示式:通過一個表示式來確定AOP要增強的是哪個或者哪些方法.
(1)前置通知:@Before 執行前置通知,並通過JointPoint獲取方法中的引數
@Aspect @Component public class DaoAspect { /* 前置通知:在執行addUser方法之前,執行前置通知,並通過JointPoint獲取addUser()方法中的引數 */ @Before("execution(* com.xzit.dao.Impl.UserDaoImpl.addUser(..))") public void methodBefore(JoinPoint joinPoint){ System.out.println("methodBefore invoked ... ..."); Object[] args = joinPoint.getArgs(); System.out.println(Arrays.toString(args)); } }
(2)後置通知:@After 切點方法是否出現異常,後置通知都會執行
(3)返回通知:@AfterReturning 切點出現異常,返回通知不會執行
(4)異常通知:@AfterThrowing 切點方法出現異常就執行,不出現異常就不執行
(5)環繞通知:@Around 在切點方法之前和之後執行。是@Before和@AfterReturing 相結合
根據任務背景,我選擇了返回通知@AfterReturning。使用返回通知一定要注意的是:由於我需要用到返回值,所以會用@AfterReturning註解中的returning屬性來獲取方法的返回值
@AfterReturning(pointcut = "@annotation(com.xxx.xxx.xxx.Log)", returning = "cId") public void handleRdLogs(JoinPoint joinPoint, int cId)
@AfterReturning(pointcut = "@annotation(com.xxx.xxx.xxx.Log)", returning = "cId") public void handleRdLogs(JoinPoint joinPoint, int cId) { // 獲取方法簽名 MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); // 獲取@Log註解內容 if (!methodSignature.getMethod().isAnnotationPresent(Log.class)) { log.error("獲取註解@Log失敗"); throw new Exception("獲取註解@Log失敗"); } Log log = methodSignature.getMethod().getAnnotation(Log.class); // 輸出紀錄檔的備註 System.out.println(log.note()) }
(1) 獲取方法簽名
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();`
(2)根據方法簽名獲取自定義註解
Log log = methodSignature.getMethod().getAnnotation(Log.class);
(3)根據自定義註解獲取,註解內部的引數
System.out.println(log.note())
場景:不僅需要獲取返回值,還得知道方法引數的值,而且方法引數的值不能作為返回值,這個該怎麼辦呢?
秀操作開始:
第一步: 在註解上寫 "#" + "方法引數的名"
@Log(note = "#note") public int rdAuditReturn(String note) { System.out.println(note) xxxx..... xxxx..... 業務程式碼..... xxxx..... xxxx.... return cId; }
第二步: 實現切面,只要呼叫這個方法,就可以得到note的值了
private final ExpressionParser parser = new SpelExpressionParser(); private final EvaluationContext evaluationContext = new StandardEvaluationContext(); private void getNote(JoinPoint joinPoint, StringBuilder noteBuilder, String note) throws NoSuchMethodException { if (!StringUtils.isBlank(note)) { Class<?> targetCls = joinPoint.getTarget().getClass(); MethodSignature ms = (MethodSignature) joinPoint.getSignature(); Method targetMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes()); ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer(); String[] parameterNames = pnd.getParameterNames(targetMethod); Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; ++i) { int index = i; Optional.ofNullable(args[i]).ifPresent(param -> { String paramName = parameterNames[index]; this.evaluationContext.setVariable(paramName, param); }); } Optional.ofNullable(this.parser.parseExpression(note).getValue(this.evaluationContext)).ifPresent(k -> noteBuilder.append((String) k) ); } }
以上就是SpringBoot 自定義註解非同步記錄複雜紀錄檔詳解的詳細內容,更多關於SpringBoot註解非同步紀錄檔記錄的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45