码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • Java里使用AspectJ实现AOP


     前言

    已经正式从NET转型JAVA。今后开始多写一点JAVA相关的文章。

    因为已经正式转Java了,所以,对于Java的一些判断,应该就比以前更准确了。总得来说,java有好的东西,有不好的东西,就语言本身和java的常用组件来讲,并不能判断,java比其他语言高一个档次,当然,也不会低一个档次。应该跟其他语言是一个段位的。

    但java的调试,确实是比较花费时间,他做不到编译成功后,就能运行成功。这里有注解的问题,有maven的问题,有组件版本的问题。总之,检测的非常不好,非常浪费时间。

    java的好处就是,团队成员比较多,毕竟开发起来真的很废人。但好处也在这里,人多,代表着,1,大家的压力都不大,人多压力就会分散。2,功能和性能有时间做的更优秀,人多就是工时多。

    而且Java工资确实相对比其他语言高。

    总体来说,java是比较幸福的。

    开始正文

    Aspectj提供一种在字符串里编程的模式,即在字符串里写函数,然后程序启动的时候会动态的把字符串里的函数给执行了。

    例如:

    "execution(* *(..))"

    这里的execution就是一个函数,我们调用它,然后传递的参数是【* *(..)】。

    Aspectj 使用
     
    使用前,我们先了解一下execution和它的参数的匹配规则:
    复制代码
    execution: 用于匹配方法执行的连接点;
    execution(public * *(..)) ==> 匹配所有目标类的public方法,第一个*代表返回类型,第二个*代表方法名,而..代表任意入参的方法。
    execution(* com.oysept.springboot.controller..*.*(..)) ==> 该包及所有子包下任何类的任何方法。
    execution(* com.oysept.springboot.controller.*(..)) ==> 该包下任何类的任何方法。
    execution(* com.oysept.springboot.controller.AspectJController.*(..)) ==> 该包下AspectJController类的任何方法。
    execution(* com..*.*Controller.method*(..)) ==> 匹配包名前缀为com的任何包下类名后缀为Controller的方法,方法名必须以method为前缀。
    execution(* *To(..)) ==> 匹配目标类所有以To为后缀的方法。
    注: 该方法只是为了声明一个公共的环绕通知,也可以直接在具体方法配置,如: @Around("execution(* com.oysept.springboot.controller..*.*(..))")
    复制代码

    @Before和@AfterReturning

    然后我们编写一个aspect的基础使用代码,如下:
    复制代码
    /**
     * @Before:定义了前置通知方法。打印出入参
     * @AfterReturning:定义了后置返回通知方法。打印出入参、返参
     */
    @Slf4j
    @Aspect
    @Component
    public class AopAspect_Basic {  
        @Before("execution(public * com.k.tender.controller.business.user.UserController.*(..))")
        public void doBefore(JoinPoint point){
            String methodName = point.getSignature().getName();
            List args = Arrays.asList(point.getArgs());
            log.info("调用前连接点方法为:" + methodName + ",参数为:" + args);
        }
    
        @AfterReturning(value = "execution(public * com.k.tender.controller.business.user.UserController.*(..))", returning = "returnValue")
        public void doAfterReturning(JoinPoint point, Object returnValue){
            String methodName = point.getSignature().getName();
            List args = Arrays.asList(point.getArgs());
            log.info("调用前连接点方法为:" + methodName + ",参数为:" + args + ",返回值为:" + returnValue);
        }
    
    }
    
    复制代码

     如上代码,我们使用了@Before和@AfterReturning注解,在UserController调用前和后,分别埋了点,并输出了函数的入参和出参。

    @Pointcut

    @Pointcut其实是一个提取execution函数的操作,就是指定一个埋点,然后使用了@Before和@AfterReturning注解时,就不用每次都写那个execution函数了,这样就不用担心写错了。
    代码示例如下:
    复制代码
      @Pointcut("execution(public * com.k.tender.controller.business.tender.TenderController.*(..))")
        public void doPointCut() {
    
        }
    
        @Before("doPointCut()")
        public void doBefore(JoinPoint point){
            String methodName = point.getSignature().getName();
            List args = Arrays.asList(point.getArgs());
            log.info("调用前连接点方法为:" + methodName + ",参数为:" + args);
        }
    
        @AfterReturning(value = "doPointCut()", returning = "returnValue")
        public void doAfterReturning(JoinPoint point, Object returnValue){
            String methodName = point.getSignature().getName();
            List args = Arrays.asList(point.getArgs());
            log.info("调用前连接点方法为:" + methodName + ",参数为:" + args + ",返回值为:" + returnValue);
        }
    
    复制代码

    对注解埋点

    有时候,我们希望编写一个注解,然后让有该注解的函数,都被拦截,那么就可以使用Aspectj的注解埋点模式。

    代码如下: 

    复制代码
    @Slf4j
    @Aspect
    @Component
    public class AopAspect_Annotation {
    
        @Before("@annotation(com.k.tender.aop.MyAop)")
        public void doBefore(JoinPoint point){
            String methodName = point.getSignature().getName();
            List args = Arrays.asList(point.getArgs());
            log.info("调用前连接点方法为:" + methodName + ",参数为:" + args);
        }
        @AfterReturning(value ="@annotation(com.k.tender.aop.MyAop)", returning = "returnValue")
        public void doAfterReturning(JoinPoint point, Object returnValue){
            String methodName = point.getSignature().getName();
            List args = Arrays.asList(point.getArgs());
            log.info("调用前连接点方法为:" + methodName + ",参数为:" + args + ",返回值为:" + returnValue);
        }
    }

    public @interface MyAop {
      String value() default "自定义注解拦截";
    }
    复制代码

    如果觉得写注解的命名空间麻烦,也可以这样写:

    复制代码
    @Before("@annotation(apiOperation)")
        public void doBefore(JoinPoint point, MyAopAsyncTask apiOperation) {
            String methodName = point.getSignature().getName();
            List args = Arrays.asList(point.getArgs());
            log.info("调用前连接点方法为:" + methodName + ",参数为:" + args);
        }
    
    复制代码

    还可以将注解和前面的excution函数结合写:

    复制代码
      @Before("execution(public * com.k..*.*(..)) && @annotation(apiOperation)") 
        public void doBefore(JoinPoint point, MyAopAsyncTask apiOperation) throws NoSuchMethodException {
            String methodName = point.getSignature().getName();
            List args = Arrays.asList(point.getArgs());
            log.info("调用前连接点方法为:" + methodName + ",参数为:" + args); 
        }
    
    复制代码

    有时候我们的拦截会触发多次,这个具体原因调查起来很麻烦,我们也可以这样解决,代码如下:

    复制代码
     private volatile long hashcode = 0;//应对重复触发
        @Before("execution(public * com.k..*.*(..)) && @annotation(apiOperation)")
    
        public void doBefore(JoinPoint point, MyAopAsyncTask apiOperation) throws NoSuchMethodException {
            if (hashcode != point.getTarget().hashCode()) {
                log.info("========doBefore========");
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = requestAttributes.getRequest();
                String method = request.getMethod();
               
            }
    
        }
    复制代码

    使用hashcode来过滤多次拦截。

     ----------------------------------------------------------------------------------------------------

     到此,Android里使用AspectJ实现AOP就介绍完了。

    ----------------------------------------------------------------------------------------------------

    注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
    若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!

    https://www.cnblogs.com/kiba/p/18027435

     

     

  • 相关阅读:
    小白必看!上位机控制单片机原理
    java基础-并发编程-ReentrantLock源码学习
    摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?
    【Linux笔记】Linux环境变量与地址空间
    16 拉格朗日定理和函数的单调性
    信息化工程测试验收管理制度
    33 WEB漏洞-逻辑越权之水平垂直越权全解
    某物联网数智化园区行业基于 KubeSphere 的云原生实践
    HLS 的新特性
    java毕业设计导师交流系统Mybatis+系统+数据库+调试部署
  • 原文地址:https://www.cnblogs.com/kiba/p/18027435
    • 最新文章
    • 【JVM】编译执行与解释执行的区别是什么?JVM 使用哪种方式?
      用 Hashids 优雅解决 C 端自增 ID 暴露问题
      V8引擎 精品漫游指南--Ignition篇(上) 指令 栈帧 槽位 调用约定 内存布局 基础内容
      LLVM Pass快速入门(四):代码插桩
      milkup:桌面端 markdown AI续写和即时渲染
      基于项目工程构建SBOM(软件物料清单)的研究
      鸿蒙应用开发UI基础第二节:鸿蒙应用程序框架核心解析与实操
      .NET 中如何快速实现 List 集合去重?
      扣子Coze实战:从0到1打造抖音+小红书热点监控智能体
      浅谈数据访问层
    • 热门文章
    • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
      奉劝各位学弟学妹们,该打造你的技术影响力了!
      五年了,我在 CSDN 的两个一百万。
      Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
      面试官都震惊,你这网络基础可以啊!
      你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
      心情不好的时候,用 Python 画棵樱花树送给自己吧
      通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
      13 万字 C 语言从入门到精通保姆级教程2021 年版
      10行代码集2000张美女图,Python爬虫120例,再上征途
    小工具 小游戏
    Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1

    京公网安备 11010502049817号