關於 Spring Boot 引用 AOP 請參考前文:【HAVENT原創】使用 Spring Boot 的 AOP 全局記錄執行時間日誌java
接下來咱們要使用自定義的註解:web
1. 首先定義一個註解接口對象spring
package com.havent.demo.aop.target; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface HHWebLog { String value() default "自動日誌開始..."; String level() default "info"; String path() default ""; }
2. 在 HHWebLogAspect.java 中建立新的切面點並關聯註解接口編程
@Pointcut(value = "@annotation(com.havent.demo.aop.target.HHWebLog)") public void webLog(){}
3. 建立 前置通知 注入方法app
@Before(pointcut = "webLog()") public void deBefore(JoinPoint joinPoint) throws Throwable { // 接收到請求,記錄請求內容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 記錄下請求內容 System.out.println("HH URL : " + request.getRequestURL().toString()); System.out.println("HH HTTP_METHOD : " + request.getMethod()); System.out.println("HH IP : " + request.getRemoteAddr()); System.out.println("HH CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); System.out.println("HH ARGS : " + Arrays.toString(joinPoint.getArgs())); //logger.trace(""); }
如需獲取註解中的參數,則代碼以下spa
@Before("@annotation(hhWebLog)") public void deBefore(JoinPoint joinPoint, HHWebLog hhWebLog) throws Throwable { // 接收到請求,記錄請求內容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 記錄下請求內容 System.out.println("HH URL : " + request.getRequestURL().toString()); System.out.println("HH HTTP_METHOD : " + request.getMethod()); System.out.println("HH IP : " + request.getRemoteAddr()); System.out.println("HH CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); System.out.println("HH ARGS : " + Arrays.toString(joinPoint.getArgs())); System.out.println("HH targe:" + hhWebLog.path()); //logger.trace(""); }
4. 建立 返回通知 注入方法.net
@AfterReturning(pointcut = "webLog()", returning = "result") public void doAfterReturning(Object result) throws Throwable { // 處理完請求,返回內容 System.out.println("HH 方法的返回值 : " + result); //logger.trace(""); }
5. 建立 後置異常 注入方法日誌
//後置異常通知 @AfterThrowing("webLog()") public void throwss(JoinPoint jp){ System.out.println("HH 方法異常時執行....."); //logger.trace(""); }
6. 建立 後置通知 注入方法code
//後置最終通知,final加強,無論是拋出異常或者正常退出都會執行 @After("webLog()") public void after(JoinPoint jp){ System.out.println("HH 方法最後執行....."); }
完整 HHWebLogAspect.java 以下對象
package com.havent.demo.aop.aspect; import com.havent.demo.aop.target.HHWebLog; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; @Aspect @Component public class HHWebLogAspect { @Pointcut(value = "@annotation(com.havent.demo.aop.target.HHWebLog)") public void webLog(){} @Before("@annotation(hhWebLog)") public void deBefore(JoinPoint joinPoint, HHWebLog hhWebLog) throws Throwable { // 接收到請求,記錄請求內容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 記錄下請求內容 System.out.println("HH URL : " + request.getRequestURL().toString()); System.out.println("HH HTTP_METHOD : " + request.getMethod()); System.out.println("HH IP : " + request.getRemoteAddr()); System.out.println("HH CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); System.out.println("HH ARGS : " + Arrays.toString(joinPoint.getArgs())); System.out.println("HH targe:" + hhWebLog.path()); //logger.trace(""); } @AfterReturning(pointcut = "webLog()", returning = "result") public void doAfterReturning(Object result) throws Throwable { // 處理完請求,返回內容 System.out.println("HH 方法的返回值 : " + result); //logger.trace(""); } //後置異常通知 @AfterThrowing("webLog()") public void throwss(JoinPoint jp){ System.out.println("HH 方法異常時執行....."); //logger.trace(""); } //後置最終通知,final加強,無論是拋出異常或者正常退出都會執行 @After("webLog()") public void after(JoinPoint jp){ System.out.println("HH 方法最後執行....."); } }
7. 外部註冊註解代碼
package com.havent.demo.controller; import com.havent.demo.aop.target.HHWebLog; import com.havent.demo.logger.service.KafkaService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @HHWebLog(level = "error", path = "/test") @RequestMapping("/test") public String test() { return "test"; } }
訪問 http://localhost:8081/test 效果以下:
那麼若是有多個 AOP 攔截器,他們的執行順序是什麼樣子的呢?
Spring AOP 就是面向切面編程,什麼是切面,畫一個圖來理解下:
由此得出:spring aop 就是一個同心圓,要執行的方法爲圓心,最外層的 order 最小。從最外層按照 AOP一、AOP2 的順序依次執行 doAround 方法,doBefore 方法。而後執行 method 方法,最後按照 AOP二、AOP1 的順序依次執行 doAfter、doAfterReturn 方法。也就是說對多個 AOP 來講,先 before 的,必定後 after。
若是咱們要在同一個方法事務提交後執行本身的 AOP,那麼把事務的 AOP order 設置爲2,本身的 AOP order 設置爲1,而後在 doAfterReturn 裏邊處理本身的業務邏輯。
同事執行前篇文章的 AOP 和本文中的自定義註解 AOP 的效果以下: