AspectJ的拓展学习--织入顺序和通知参数指定
前言:
其实spring的aop非常的强大, 因此研究一下AspectJ还是有必要, 而不是仅仅停留在初级的阶段.
比如spring的事务是基于aop来实现的, 如果不能深入的研究, 可能很多知识点, 只知其然而不知其所以然.
本文将简单地讲述如何指定AspectJ的织入顺序, 以及如何指定通知参数.
AspectJ的博文:
以下博文是之前实战中记录的.
1. 利用Aspectj实现Oval的自动参数校验
2. 类Shiro权限校验框架的设计和实现
以下博文是本文参考的文章(强烈推荐):
1. AspectJ切入点语法详解
织入顺序:
如果同一个函数调用, 涉及多个AOP的织入, 那么这些AOP的顺序该如何定义和指定? 为了解决这个问题, AspectJ引入了Order, 它约定了order数值越小, 优先级越高(越早被调用).
AspectJ类指定顺序的方式有两种.
1. 引入注解@Order
import org.springframework.core.annotation.Order; @Aspect
@Component
@Order(1)
public class MyAdvice1 { @Pointcut("execution(* com.springapp.mvc.controller.*.*(..))")
public void pointCut() {
} }
2. 实现Ordered接口
import org.springframework.core.Ordered; @Aspect
@Component
public class MyAdvice2 implements Ordered { @Pointcut("execution(* com.springapp.mvc.controller.*.*(..))")
public void pointCut() {
} @Override
public int getOrder() {
return 2;
} }
无论是那种, 其遵守的标准是一定的.
总的来说, 其顺序规则如下:
1. 在同一切面类内, 按照切入点的定义顺序来织入
2. 在不同的切面类内, 都实现了Ordered接口, 按切入点的Order数值从小到达织入.
3. 在不同的切面类内, 存在没实现Ordered接口的类, 则切入点的顺序不确定.
通知参数指定:
通知参数的指定, 一定程度上是为方便编程, 提升了开发效率.
我之前对Aspectj了解没那么深入的时候, 一直用吃力不讨好的方式在开发.
比如之前写的权限校验小框架, 其核心代码如下:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRequiresRoles {
String[] value();
MyLogic logic() default MyLogic.AND;
}
@Aspect
@Component
public class MyShiroAdvice {
/**
* 定义切点, 用于角色的校验
*/
@Pointcut("@annotation(com.springapp.mvc.myshiro.MyRequiresRoles)")
public void checkRoles() {
}
@Before("checkRoles()")
public void doCheckRole(JoinPoint jp) throws Exception {
// *) 从JointPoint变量中提取对应的注解
MyRequiresRoles mrp = extractAnnotation(
(MethodInvocationProceedingJoinPoint)jp,
MyRequiresRoles.class
);
try {
// 获取注解设置的值(角色集合, 逻辑操作), 进行评估判断
if ( !MyShiroHelper.validateRoles(mrp.value(), mrp.logic()) ) {
throw new Exception("access disallowed");
}
} catch (Exception e) {
throw new Exception("invalid state");
}
}
// *) 获取注解信息
private static <T extends Annotation> T extractAnnotation(
MethodInvocationProceedingJoinPoint mp, Class<T> clazz) throws Exception {
Field proxy = mp.getClass().getDeclaredField("methodInvocation");
proxy.setAccessible(true);
ReflectiveMethodInvocation rmi = (ReflectiveMethodInvocation) proxy.get(mp);
Method method = rmi.getMethod();
return (T) method.getAnnotation(clazz);
}
}
在具体的拦截方法中, 通过JointPoint对象, 获取对应的调用方法/注解/参数等信息. 但这种方式不够简洁, 容易导致类型转换错误.
是否有一种办法, 能够做到所需参数的随叫随到, 而且避免了类型转换的坑.
答案是肯定的, 这为大英雄就是通知参数指定.
针对上面一个列子, 我们可以引入切面指示符@annotation类实现:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRequiresRoles {
String[] value();
MyLogic logic() default MyLogic.AND;
}
@Aspect
@Component
public class MyShiroAdvice {
/**
* 定义切点, 用于角色的校验
*/
@Pointcut("@annotation(com.springapp.mvc.myshiro.MyRequiresRoles)")
public void checkRoles() {
}
// *) 通知参数指定, 通过指示符@annotation()指定了注解@MyRequiresRoles参数
@Before("checkRoles() && @annotation(mrp)")
public void doCheckRole(MyRequiresRoles mrp) throws Exception {
try {
if ( !MyShiroHelper.validateRoles(mrp.value(), mrp.logic()) ) {
throw new Exception("access disallowed");
}
} catch (Exception e) {
throw new Exception("invalid state");
}
}
}
注: 对比上述两个代码, 功能不变, 却直接导入想要的注解信息(间接地规避了类型转换), 大大简化了代码编写.
我们再来一个切面指示符args的使用例子:
@Before(value = "checkRoles() && args(k, v)", argNames = "k, v")
public void doCheckRole2(String k, String v) {
// TODO
}
注: 只有满足切面checkRole()规则, 同时调用函数签名的参数列表为methodName(String, String), 才触发调用.
这个例子确实轻而易举的获取了调用函数的参数.
AspectJ指示符:
举例一下常见的一些指示符:
execution:用于匹配方法执行的连接点.
within:用于匹配指定类型内的方法执行.
this:用于匹配当前AOP代理对象类型的执行方法, 注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配.
target:用于匹配当前目标对象类型的执行方法, 注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配.
args:用于匹配当前执行的方法传入的参数为指定类型的执行方法.
@annotation:用于匹配当前执行方法持有指定注解的方法.
reference pointcut:表示引用其他命名切入点.
总结:
通过查阅一些资料, 以及自己的一些demo程序测试, 对Aspectj还是有一些收获的.
AspectJ的拓展学习--织入顺序和通知参数指定的更多相关文章
- 曹工说Spring Boot源码(13)-- AspectJ的运行时织入(Load-Time-Weaving),基本内容是讲清楚了(附源码)
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- Spring AOP: 织入的顺序
spring AOP 采用和 AspectJ 一样的优先顺序来织入增强处理:在进入连接点时,高优先级的增强处理将先被织入:在退出连接点时,高优先级的增强处理会后被织入. 当不同的切面里的两个增强处理需 ...
- Spring的LoadTimeWeaver(代码织入)
在Java 语言中,从织入切面的方式上来看,存在三种织入方式:编译期织入.类加载期织入和运行期织入.编译期织入是指在Java编译期,采用特殊的编译器,将切面织入到Java类中:而类加载期织入则指通过特 ...
- Spring的LoadTimeWeaver(代码织入)(转)
https://www.cnblogs.com/wade-luffy/p/6073702.html 在Java 语言中,从织入切面的方式上来看,存在三种织入方式:编译期织入.类加载期织入和运行期织入. ...
- AOP的核心:代理与织入
分为两步: 1.动态生成代理类: 2.织入: 2.6 织入(Weaving) 织入是将增强添加到目标的具体连接点上的过程 . AOP 织入方式: 方式 实现 应用编译期织入 特殊的 Java 编译器. ...
- 黑马Spring学习 AOP XML和注解配置 5种通知 切点切面通知织入
业务类 package cn.itcast.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoin ...
- 框架源码系列三:手写Spring AOP(AOP分析、AOP概念学习、切面实现、织入实现)
一.AOP分析 问题1:AOP是什么? Aspect Oriented Programming 面向切面编程,在不改变类的代码的情况下,对类方法进行功能增强. 问题2:我们需要做什么? 在我们的框架中 ...
- Spring AOP 之编译期织入、装载期织入、运行时织入(转)
https://blog.csdn.net/wenbingoon/article/details/22888619 一 前言 AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP ...
- 30个类手写Spring核心原理之AOP代码织入(5)
本文节选自<Spring 5核心原理> 前面我们已经完成了Spring IoC.DI.MVC三大核心模块的功能,并保证了功能可用.接下来要完成Spring的另一个核心模块-AOP,这也是最 ...
随机推荐
- D3生成树专题
这一天不知道怎的上课 竟然我说了两道题正解: 第一题:我写过一篇较详细的博客:https://www.cnblogs.com/Tyouchie/p/10366967.html 第二题:UVA10369 ...
- 剑指offer(6)旋转数组中的最小数字
题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个 ...
- jQuery实现淘宝购物车小组件
我爱撸码,撸码使我感到快乐! 大家好,我是Counter,本章将实现淘宝购物车小组件, 用原生js可以实现吗,当然可以,可是就是任性一回,就是想用jQuery 来实现下.HTML代码不多才4行,CSS ...
- 使用C#加密及解密字符串
using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace Util ...
- 自制URL转换器
自定义 url 转换器五个步骤: 定义一个类. 在类中定义一个属性 regex ,这个属性是用来保存 url 转换器规则的正则表达式. 实现 to_python(self,value) 方法, ...
- 三 drf 认证,权限,限流,过滤,排序,分页,异常处理,接口文档,集xadmin的使用
因为接下来的功能中需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员. python manage.py createsuperuser 创建管理员以后,访问admin站点 ...
- Windows下命令行怎样登录MySQL
直接cmd回车然后 “ mysql -u root -p ” 登录时出现错误,原来是权限不够 打开cmd时需要以管理员的身份打开 然后继续使用 “ mysql -u root -p ” 还是不行, ...
- postman(八):使用newman来执行postman脚本
通过之前的了解,我们知道postman是基于javascript语言编写的,而导出的json格式的postman脚本也无法直接在服务器运行,它需要在newman中执行(可以把newman看做postm ...
- LeetCode--015--三元之和(java)
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...
- JAVA文件操作类和文件夹的操作代码示例
JAVA文件操作类和文件夹的操作代码实例,包括读取文本文件内容, 新建目录,多级目录创建,新建文件,有编码方式的文件创建, 删除文件,删除文件夹,删除指定文件夹下所有文件, 复制单个文件,复制整个文件 ...