本文采用SpringBoot技术编写一个Spring AOP 示例。

一、引入依赖

  1. <!--引入AOP依赖-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-aop</artifactId>
  5. </dependency>

:::warning 注意:在完成了引入AOP依赖包后,不需要去做其他配置。AOP的默认配置属性中,spring.aop.auto属性默认是开启的,也就是说只要引入了AOP依赖后,默认已经增加了@EnableAspectJAutoProxy,不需要在程序主类中增加@EnableAspectJAutoProxy来启用。 :::

二、定义切面

定义切面类:在类上添加@Aspect 和@Component 注解即可将一个类定义为切面类。
@Aspect 注解 使之成为切面类
@Component 注解 把切面类加载到到IOC容器中,Bean交给Spring容器管理

  1. package com.king.aop.aspect;
  2. import org.aspectj.lang.JoinPoint;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.*;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.stereotype.Component;
  8. import org.springframework.web.context.request.RequestContextHolder;
  9. import org.springframework.web.context.request.ServletRequestAttributes;
  10. import javax.servlet.http.HttpServletRequest;
  11. import java.util.Arrays;
  12. import java.util.Objects;
  13. /**
  14. * 日志切面
  15. * @PackageName com.king.aop.aspect
  16. * @ClassName LogAspect
  17. * @Auther jgg
  18. * @Date 2021-7-5 10:16
  19. */
  20. @Aspect
  21. @Component
  22. public class LogAspect {
  23. private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
  24. @Pointcut("execution(public * com.king.aop.controller.*.*(..))")
  25. public void webLog(){}
  26. /*前置通知*/
  27. @Before("webLog()")
  28. public void doBefore(JoinPoint joinPoint) throws Throwable{
  29. //接收到请求,记录请求信息
  30. ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  31. HttpServletRequest request= attributes.getRequest();
  32. //记录请求信息
  33. System.out.println("URL" + request.getRequestURL().toString());
  34. System.out.println("request.getMethod() = " + request.getMethod());
  35. System.out.println("IP:" + request.getRemoteHost());
  36. System.out.println("Class+Methord" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
  37. System.out.println("params" + Arrays.toString(joinPoint.getArgs()));
  38. logger.info("user ip: {}",request.getRemoteAddr());
  39. }
  40. //后置异常通知
  41. @AfterThrowing("webLog()")
  42. public void throwss(JoinPoint jp){
  43. System.out.println("方法异常时执行...");
  44. }
  45. //后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
  46. @After("webLog()")
  47. public void after(JoinPoint jp){
  48. System.out.println("方法最后执行...");
  49. }
  50. @AfterReturning(returning = "obj",pointcut = "webLog()")
  51. public void doAfterReturing(Objects obj) throws Throwable{
  52. System.out.println("方法返回值为:"+obj);
  53. logger.info("方法返回值为: {}",obj);
  54. }
  55. /**
  56. * 环绕通知
  57. * @param point
  58. * @throws Throwable
  59. */
  60. @Around("webLog()")
  61. public void doAround(ProceedingJoinPoint point) throws Throwable{
  62. System.out.println("方法环绕Running...");
  63. try {
  64. Object proceed = point.proceed();
  65. System.out.println("方法环绕proceed,结果是 :" + proceed);
  66. logger.info("方法返回值:{}",proceed);
  67. } catch (Throwable throwable) {
  68. throw throwable;
  69. }
  70. }
  71. }

采用自定义注解的形式实现 Spring AOP

自定义注解

  1. import java.lang.annotation.ElementType;
  2. import java.lang.annotation.Retention;
  3. import java.lang.annotation.RetentionPolicy;
  4. import java.lang.annotation.Target;
  5. /**
  6. * @PackageName com.king.aop.aspect
  7. * @ClassName UserAspect
  8. * @Auther jgg
  9. * @Date 2021-7-6 9:31
  10. */
  11. @Target({ElementType.METHOD,ElementType.TYPE})
  12. @Retention(RetentionPolicy.RUNTIME)
  13. public @interface UserAccess {
  14. String desc() default "No Data!";
  15. }

定义切面

  1. package com.king.aop.aspect;
  2. import org.aspectj.lang.JoinPoint;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.*;
  5. import org.springframework.stereotype.Component;
  6. import java.util.Date;
  7. /**
  8. * @PackageName com.king.aop.aspect
  9. * @ClassName UserAccessAspect
  10. * @Auther jgg
  11. * @Date 2021-7-6 9:35
  12. */
  13. @Component
  14. @Aspect
  15. public class UserAccessAspect {
  16. @Pointcut(value ="@annotation(com.king.aop.aspect.UserAccess)")
  17. public void access(){
  18. }
  19. @Before("access()")
  20. public void doBefore(JoinPoint point){
  21. System.out.println("-aop 日志记录启动-" + new Date());
  22. }
  23. /*环绕通知*/
  24. @Around("@annotation(userAccess)")
  25. public Object around(ProceedingJoinPoint pjp, UserAccess userAccess) {
  26. //获取注解里的值
  27. System.out.println("second around:" + userAccess.desc());
  28. try {
  29. return pjp.proceed();
  30. } catch (Throwable throwable) {
  31. throwable.printStackTrace();
  32. return null;
  33. }
  34. }
  35. //进来切点这,最后经过的一个站,也是方法正常运行结束后
  36. @After("access()")
  37. public void after(JoinPoint joinPoint) {
  38. System.out.println("-aop 日志记录结束-" + new Date());
  39. }
  40. }

三、知识补充

切点表达式

https://www.cnblogs.com/javazhiyin/p/9993299.html
原文链接:https://blog.csdn.net/qq_35387940/article/details/85261279
https://www.cnblogs.com/zhangxufeng/p/9160869.html