关于 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 的效果以下: