Android里使用AspectJ实现AOP
前言
已经正式从NET转型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<Object> 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<Object> 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<Object> 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<Object> 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<Object> 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<Object> args = Arrays.asList(point.getArgs()); log.info("调用前连接点方法为:" + methodName + ",参数为:" + args + ",返回值为:" + returnValue); } }
public @interface MyAop {
String value() default "自定义注解拦截";
}
String value() default "自定义注解拦截";
}
如果觉得写注解的命名空间麻烦,也可以这样写:
@Before("@annotation(apiOperation)") public void doBefore(JoinPoint point, MyAopAsyncTask apiOperation) { String methodName = point.getSignature().getName(); List<Object> 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<Object> 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
https://www.cnblogs.com/kiba/