前言

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

例如:

  1. "execution(* *(..))"

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

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

@Before和@AfterReturning

然后我们编写一个aspect的基础使用代码,如下:
  1. /**
  2. * @Before:定义了前置通知方法。打印出入参
  3. * @AfterReturning:定义了后置返回通知方法。打印出入参、返参
  4. */
  5. @Slf4j
  6. @Aspect
  7. @Component
  8. public class AopAspect_Basic {
  9. @Before("execution(public * com.k.tender.controller.business.user.UserController.*(..))")
  10. public void doBefore(JoinPoint point){
  11. String methodName = point.getSignature().getName();
  12. List<Object> args = Arrays.asList(point.getArgs());
  13. log.info("调用前连接点方法为:" + methodName + ",参数为:" + args);
  14. }
  15.  
  16. @AfterReturning(value = "execution(public * com.k.tender.controller.business.user.UserController.*(..))", returning = "returnValue")
  17. public void doAfterReturning(JoinPoint point, Object returnValue){
  18. String methodName = point.getSignature().getName();
  19. List<Object> args = Arrays.asList(point.getArgs());
  20. log.info("调用前连接点方法为:" + methodName + ",参数为:" + args + ",返回值为:" + returnValue);
  21. }
  22.  
  23. }

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

@Pointcut

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

对注解埋点

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

代码如下:

  1. @Slf4j
  2. @Aspect
  3. @Component
  4. public class AopAspect_Annotation {
  5.  
  6. @Before("@annotation(com.k.tender.aop.MyAop)")
  7. public void doBefore(JoinPoint point){
  8. String methodName = point.getSignature().getName();
  9. List<Object> args = Arrays.asList(point.getArgs());
  10. log.info("调用前连接点方法为:" + methodName + ",参数为:" + args);
  11. }
  12. @AfterReturning(value ="@annotation(com.k.tender.aop.MyAop)", returning = "returnValue")
  13. public void doAfterReturning(JoinPoint point, Object returnValue){
  14. String methodName = point.getSignature().getName();
  15. List<Object> args = Arrays.asList(point.getArgs());
  16. log.info("调用前连接点方法为:" + methodName + ",参数为:" + args + ",返回值为:" + returnValue);
  17. }
  18. }

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

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

  1. @Before("@annotation(apiOperation)")
  2. public void doBefore(JoinPoint point, MyAopAsyncTask apiOperation) {
  3. String methodName = point.getSignature().getName();
  4. List<Object> args = Arrays.asList(point.getArgs());
  5. log.info("调用前连接点方法为:" + methodName + ",参数为:" + args);
  6. }

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

  1. @Before("execution(public * com.k..*.*(..)) && @annotation(apiOperation)")
  2. public void doBefore(JoinPoint point, MyAopAsyncTask apiOperation) throws NoSuchMethodException {
  3. String methodName = point.getSignature().getName();
  4. List<Object> args = Arrays.asList(point.getArgs());
  5. log.info("调用前连接点方法为:" + methodName + ",参数为:" + args);
  6. }

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

  1. private volatile long hashcode = 0;//应对重复触发
  2. @Before("execution(public * com.k..*.*(..)) && @annotation(apiOperation)")
  3.  
  4. public void doBefore(JoinPoint point, MyAopAsyncTask apiOperation) throws NoSuchMethodException {
  5. if (hashcode != point.getTarget().hashCode()) {
  6. log.info("========doBefore========");
  7. ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  8. HttpServletRequest request = requestAttributes.getRequest();
  9. String method = request.getMethod();
  10.  
  11. }
  12.  
  13. }

使用hashcode来过滤多次拦截。

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

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

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

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

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

Android里使用AspectJ实现AOP的更多相关文章

  1. Spring @AspectJ 实现AOP 入门例子(转)

    AOP的作用这里就不再作说明了,下面开始讲解一个很简单的入门级例子. 引用一个猴子偷桃,守护者守护果园抓住猴子的小情节. 1.猴子偷桃类(普通类): package com.samter.common ...

  2. (转)Spring使用AspectJ进行AOP的开发:注解方式

    http://blog.csdn.net/yerenyuan_pku/article/details/69790950 Spring使用AspectJ进行AOP的开发:注解方式 之前我已讲过Sprin ...

  3. AspectJ对AOP的实现

    一:你应该明白的知识 1.对于AOP这种编程思想,很多框架都进行了实现.Spring就是其中之一,可以完成面向切面编程.然而,AspectJ也实现了AOP的功能,且实现方式更为简捷,使用更加方便,而且 ...

  4. 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式

    注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...

  5. Spring框架(6)---AspectJ实现AOP

    AspectJ实现AOP 上一篇文章Spring框架(4)---AOP讲解铺垫,讲了一些基础AOP理解性的东西,那么这篇文章真正开始讲解AOP 通过AspectJ实现AOP要比普通的实现Aop要方便的 ...

  6. 使用java5的注解和Sping/AspectJ的AOP 来实现Memcached的缓存

    使用java5的注解和Sping/AspectJ的AOP 来实现Memcached的缓存 今天要介绍的是Simple-Spring-Memcached,它封装了对MemCached的调用,使MemCa ...

  7. 8 -- 深入使用Spring -- 4...2 使用AspectJ实现AOP

    8.4.2 使用AspectJ实现AOP AspectJ是一个基于Java语言的AOP框架.Spring 4.0 的AOP对AspectJ很好的集成. AspectJ是Java 语言的一个AOP实现, ...

  8. spring3: schema的aop与Aspectj的aop的区别

    schema的aop如下: 接口: package chapter6.service; public interface IHelloAroundService { public void sayAr ...

  9. Spring整合AspectJ的AOP

    学而时习之,不亦说乎!                              --<论语> 看这一篇之前最好先看前面关于AOP的两篇. http://www.cnblogs.com/z ...

  10. 利用基于@AspectJ的AOP实现权限控制

    一. AOP与@AspectJ AOP 是 Aspect Oriented Programming 的缩写,意思是面向方面的编程.我们在系统开发中可以提取出很多共性的东西作为一个 Aspect,可以理 ...

随机推荐

  1. 部分MySQL的SQL信息整理

    模块补丁信息查看 select su as 补丁模块, count(1) as 数量 from gsppatchlog where TO_DAYS( NOW( ) ) - TO_DAYS(deploy ...

  2. [转帖]内存管理参数zone_reclaim_mode分析

    zone_reclaim_mode 官方解释 调整方法 调整的影响 官方解释 最近在性能优化,看到了zone_reclaim_mode参数,记录备用 zone_reclaim_mode: Zone_r ...

  3. [转帖]TiDB 热点问题处理

    TiDB 热点问题处理 本文介绍如何定位和解决读写热点问题. TiDB 作为分布式数据库,内建负载均衡机制,尽可能将业务负载均匀地分布到不同计算或存储节点上,更好地利用上整体系统资源.然而,机制不是万 ...

  4. Stream的简单学习

    Stream的简单学习 前言 https://github.com/jeffhammond/STREAM unzip STREAM-master.zip cd /STREAM-master/ make ...

  5. [转帖]linux求数组的交集,shell/bash 交集、并集、差集

    方法一(直接用文件名):取两个文本文件的并集.交集.差集 并: sort -m 交: sort -m 差 file1 - file2: sort -m 方法二(用变量参数):取两个文本文件的并集.交集 ...

  6. Redis7.0 编译安装以及简单创建Cluster测试服务器的方法

    背景 北京时间2022.4.27 晚上九点半左右, Redis 7.0.0 已经GA. 为了进行简单的学习, 这边进行了简单验证工作. 本次主要分为编译, 测试集群搭建,以及springboot进行简 ...

  7. Gin-官方文档

    目录 官方文档 官方文档 https://learnku.com/docs/gin-gonic/2018/gin-readme/3819 https://www.kancloud.cn/shuangd ...

  8. minIO系列文章01---MinIO 简介

    MinIO.jpeg MinIO 官网 MinIO 官方GitHub MinIO 官方文档 1.什么是对象存储? 关于对象存储,我们可以看下 阿里云OSS 的解释. 对象存储服务OSS(Object ...

  9. python快速入门【四】-----各类函数创建

    python入门合集: python快速入门[一]-----基础语法 python快速入门[二]----常见的数据结构 python快速入门[三]-----For 循环.While 循环 python ...

  10. 19.4 Boost Asio 远程命令执行

    命令执行机制的实现与原生套接字通信一致,仅仅只是在调用时采用了Boost通用接口,在服务端中我们通过封装实现一个run_command函数,该函数用于发送一个字符串命令,并循环等待接收客户端返回的字符 ...