• Spring AOP(二)自定义注解


    需求来源:

    在记录系统调用日志时,可以使用 @Pointcut("execution(* com.service.mycontroller.controller.*.*(..))")
    指定拦截某些类或方法。但是在调用第三方系统时,调用代码可能分布在各个层不同的类和方法中,没办法使用execution表达式精确定位。此时可以自定义一个注解,在使用的方法上添加该注解即可拦截记录日志(像@Transaction一样)。

    1、自定义一个注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @Documented
    public @interface SaveLog {
    
        //调用系统枚举类
        RequestType value();
           
         //不使用枚举类
        //String systemName() default "";
    
        //String operation() default "";
    
        //String url() default "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}):
      使用范围接口、类、枚举、注解、方法、字段
    • @Retention(RetentionPolicy.RUNTIME):
      @Retention是用来修饰注解的生命周期的,RetentionPolicy.RUNTIME代表的是不仅被保存到class文件中,jvm加载class文件之后,仍然存在;一直有效!
    • @Documented:
      @Documented和@Deprecated注解长得有点像,@Deprecated是用来标注某个类或者方法不建议再继续使用,@Documented只能用在注解上,如果一个注解@B,被@Documented标注,那么被@B修饰的类,生成Javadoc文档时,会显示@B。

    2、系统及操作类型枚举类

    /**
     * @Author shallWe
     * @Date 2023-10-09 11:23
     */
    public enum RequestType {
        
        SYSTEM1_ADDUSER("system1","addUser"),
        SYSTEM1_UPDATEUSER("system1","updateUser"),
        SYSTEM1_DELETEUSER("system1","deleteUser"),
        SYSTEM2_ADD("system2","add"),
        SYSTEM2_UPDATE("system2","update"),
        SYSTEM2_DELETE("system2","delete");
    
        private String systemName;
    
        private String operation;
    
        public String getType() {
            return systemName;
        }
    
        public String getUrl() {
            return operation;
        }
    
        RequestType(String systemName, String operation) {
            this.systemName = systemName;
            this.operation = operation;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3、创建切面类

    /**
     * @Author shallWe
     * @Date 2023-10-09 11:45
     */
    @Component
    @Aspect
    public class SouthRequestLogAspect {
    
        @Pointcut("@annotation(com.service.common.SaveLog)")
        public void requestLog() {
        }
    
        @AfterReturning(returning="retObj", pointcut = "requestLog()")
        public void doAfterReturning(JoinPoint joinPoint, Object retObj){
            //获取系统名称和操作类型
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            SaveLog saveLog = signature.getMethod().getAnnotation(SaveLog.class);
            if (saveLog != null) {
                System.out.println(saveLog.value().getSystemName());
                System.out.println(saveLog.value().getOperation());
            }
            // 这里只是一个示例,你可以写任何处理逻辑
            System.out.println("---------Before触发了----------");
            // 获取签名
            Signature signature = joinPoint.getSignature();
            // 获取切入的包名
            String declaringTypeName = signature.getDeclaringTypeName();
            // 获取即将执行的方法名
            String funcName = signature.getName();
            log.info("即将执行方法为: {},属于{}包", funcName, declaringTypeName);
    
            // 也可以用来记录一些信息,比如获取请求的 URL 和 IP
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            // 获取请求 URL
            String url = request.getRequestURL().toString();
            // 获取请求 IP
            String ip = request.getRemoteAddr();
            log.info("用户请求的url为:{},ip地址为:{}", url, ip);
    
            //获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            //获取请求的方法名
            String methodName = method.getName();
            //请求的参数
            Object[] args = joinPoint.getArgs();
            //将参数所在的数组转换成json
            String params = JsonUtil.getStringFromArray(args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    4、注解使用

    此时便可以在任何方法上使用@SaveLog进行拦截处理了

        @SaveLog(RequestType.SYSTEM1_ADDUSER)
        public void system1Add(){
            System.out.println("调用A系统");
        }
    
        @SaveLog(RequestType.SYSTEM2_ADDUSER)
        public void systemAdd(){
            System.out.println("调用B系统");
        }
        
        //不使用枚举类
        //@SaveLog(systemName = "A系统", operation = "add", url = "/123/123")
        //public void system1Add(){
        //    System.out.println("调用A系统");
        //}
    
        //@SaveLog(systemName = "B系统", operation = "delete", url = "/123/123")
        //public void systemAdd(){
        //    System.out.println("调用B系统");
        //}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    更多AOP信息:Spring AOP 详解

  • 相关阅读:
    DNS有什么作用 43.227.220.X
    C++自学精简教程 目录(必读)
    Python 之Mysql的异步操作库 aiomysql 笔记
    西南科技大学814考研一
    0915练习
    多线程(73)什么时候应该使用自旋锁而不是阻塞锁
    Elasticsearch-05-Elasticsearch-sql组件史上最全详解
    2023年6月电子学会Python等级考试试卷(五级)答案解析
    ubuntu22.10 安装nginx笔记集成nginx-rtmp-module打包编译全文
    LaTeX总结-2023年9月8日
  • 原文地址:https://blog.csdn.net/qq_40774600/article/details/133706364