Spring Aop——给Advice传递参数
给Advice传递参数
Advice除了可以接收JoinPoint(非Around Advice)或ProceedingJoinPoint(Around Advice)参数外,还可以直接接收与切入点方法执行有关的对象,比如切入点方法参数、切入点目标对象(target)、切入点代理对象(this)等。
5.1 获取切入点方法参数
假设我们现在有一个id为userService的bean中定义了一个findById(int id)方法,我们希望定义一个Advice来拦截这个方法,并且把findById()的参数作为Advice处理方法的参数,即每次调用findById()传递的参数都将传递到Advice处理方法,那么我们可以如下这样定义。
@Before(value="bean(userService) && execution(* findById(java.lang.Integer)) && args(id)", argNames="id")
public void beforeWithParam(JoinPoint joinPoint, Integer id) {
System.out.println(this.getClass().getName()+" ID is : " + id);
}
上面这种定义是非常精确的定义,我们通过表达式“bean(userService) && execution(* findById(java.lang.Integer))”就已经明确的指定了我们需要拦截的是id或name为userService的findById(Integer)方法,后面又加了一个args(id)是干什么用的呢?它的作用跟findById(Integer)是类似的,它表示我们的切入点方法必须只接收一个参数,而且这个参数的类型是和当前定义的Advice处理方法的参数id是相同类型的,在上面的示例中其实就是要求是Integer类型的;另外它还有一个非常重要的作用,通过这种指定后对应的Advice处理方法在执行时将接收到与之对应的切入点方法参数的值。在上面的示例中笔者特意给Advice处理方法加了一个JoinPoint参数是为了说明JoinPoint、ProceedingJoinPoint参数是可以直接定义在Advice方法的第一个参数,并且是可以与其它接收的参数共存的。其实如果我们不只是需要拦截findById(Integer)方法,而是需要拦截id为userService的bean中所有接收一个int/Integer参数的方法,那么我们可以把上面的配置简化为如下这样。
@Before(value="bean(userService) && args(id)", argNames="id")
public void beforeWithParam2(int id) {
System.out.println(this.getClass().getName()+" ID is : " + id);
}
如果我们需要拦截的方法可能是有多个参数的,但我们只关注第一个参数,那我们可以把表达式调整为如下这样,只关注第一个参数为int/Integer类型的,并且在Advice方法中接收这个方法参数进行相应的处理。
@Before(value="bean(userService) && args(id,..)", argNames="id")
public void beforeWithParam2(int id) {
System.out.println(this.getClass().getName()+" ID is : " + id);
}
5.2 argNames参数
我们可以看到在上述例子中我们都指定了@Before的argNames属性的值为id,那么这个argNames属性有什么作用呢?argNames属性是用于指定在表达式中应用的参数名与Advice方法参数是如何对应的,argNames中指定的参数名必须与表达式中的一致,可以与Advice方法参数名不一致;当表达式中使用了多个参数时,argNames中需要指定多个参数,多个参数之间以英文逗号分隔,这些参数的顺序必须与对应的Advice方法定义的参数顺序是一致的。比如下面这个示例中,我们在Pointcut表达式中使用了name和sex两个参数,我们的Advice处理方法接收两个参数,分别是sex1和name1,我们希望Pointcut表达式中的name参数是对应的Advice处理方法的第二个参数,即name1,希望Pointcut表达式中的sex参数是对应的Advice处理方法的第一个参数,即sex1,那么我们在指定@Before注解的argNames参数时必须定义name和sex参数与Advice处理方法参数的关系,且顺序要求与对应的处理方法的参数顺序一致,即哪个参数是需要与Advice处理方法的第一个参数匹配则把哪个参数放第一位,与第二个参数匹配的则放第二位,在我们的这个示例中就应该是sex放第一位,name放第二位。
@Before(value="bean(userService) && args(name, sex)", argNames="sex, name")
public void beforeWithParam3(int sex1, String name1) {
System.out.println("sex is : " + sex1);
System.out.println("name is : " + name1);
}
@Before注解的argNames参数不是必须的,它只有在我们编译的字节码中不含DEBUG信息或Pointcut表达式中使用的参数名与Advice处理方法的参数名不一致时才需要。所以在编译的字节码中包含DEBUG信息且Advice参数名与Pointcut表达式中使用的参数名一致时,我们完全可以把argNames参数省略。如果表达式里面使用了多个参数,那么这些参数在表达式中的顺序可以与Advice方法对应参数的顺序不一致,例如下面这个样子。
@Before(value="bean(userService) && args(id)")
public void beforeWithParam2(int id) {
System.out.println(this.getClass().getName()+" ID is : " + id);
}
5.3 获取this对象
this对象就是Spring生成的bean的那个代理对象。如下示例就是Advice方法接收this对象,我们给Advice方法指定一个需要拦截的this对象类型的参数,然后在表达式中使用this类型的表达式定义,表达式中定义的对应类型指定为Advice方法参数。
@Before("this(userService)")
public void beforeWithParam4(IUserService userService) {
//this对象应该是一个代理对象
System.out.println(this.getClass().getName()+"==============传递this对
象: " + userService.getClass());
}
5.4 混合使用
我们的Advice方法可以同时接收多个目标方法参数,与此同时它也可以接收this等对象,即它们是可以混合使用的。下面这个示例中我们就同时接收了this对象和目标方法int/Interger类型的参数。
@Before("this(userService) && args(id)")
public void beforeWithParam5(IUserService userService, int id) {
System.out.println(this.getClass().getName()+"===========" + id +
"==============" + userService.getClass());
}
5.5 获取target对象
获取target对象也比较简单,只需要把表达式改为target类型的表达式即可。
@Before("target(userService)")
public void beforeWithParam6(IUserService userService) {
System.out.println(this.getClass().getName()+"==============传递
target对象: " + userService.getClass());
}
5.6 获取注解对象
当我们的Pointcut表达式类型是通过注解匹配时,我们也可以在Advice处理方法中获取匹配的注解对象,如下面这个示例,其它如使用@target等是类似的。
@Before("@annotation(annotation)")
public void beforeWithParam7(MyAnnotation annotation) {
System.out.println(this.getClass().getName()+"==============传递标
注在方法上的annotation: " + annotation.annotationType().getName());
}
5.7 泛型参数
有的时候我们的Advice方法需要接收的切入点方法参数定义的不是具体的类型,而是一个泛型,这种情况下怎么办呢?可能你会想那我就把对应的Advice方法参数定义为Object类型就好了,反正所有的类型都可以转换为Object类型。对的,这样是没有错的,但是说如果你只想拦截某种具体类型的参数调用时就可以不用把Advice方法参数类型定义为Object了,这样还得在方法体里面进行判断,我们可以直接把Advice方法参数类型定义为我们想拦截的方法参数类型。比如我们有下面这样一个使用了泛型的方法定义,我们希望只有在调用testParam方法时传递的参数类型是Integer类型时才进行拦截。
public <T> void testParam(T param);
那这个时候我们就可以把我们的Advice的表达式定义为如下这样,前者精确定义接收方法名为testParam,返回类型为void,后者精确定义方法参数为一个Integer类型的参数,其实前者也可以定义为“execution(void testParam(Integer))”。看到这你可能会想,为什么不直接把表达式定义为“execution(void testParam(param))”呢?因为execution是不支持Advice方法参数绑定的,基本上支持Advice参数绑定的就只有this、target、args以及对应的注解形式加@annotation。
@Before("execution(void testParam(..)) && args(param)")
public void beforeWithParam8(Integer param) {
System.out.println("pointcut expression[args(param)]--------------param:" +
param);
}
以上就是常用的传递参数给Advice处理方法的方式,有一些示例可能没有讲到,比如@target这种,这些其实都是类似的。包括上面我们都是以@Before这种Advice来讲的,其实其它的Advice在接收参数的时候也是类似的。
Spring Aop——给Advice传递参数的更多相关文章
- spring aop通过joinpoint传递参数
三.总结. 我们可以通过Advice中添加一个JoinPoint参数,这个值会由spring自动传入,从JoinPoint中可以取得. 三.总结. 我们可以通过Advice中添加一个JoinPoint ...
- Spring AOP切面的时候参数的传递
Spring AOP切面的时候参数的传递 Xml: <?xml version="1.0" encoding="UTF-8"?> <beans ...
- spring aop 利用JoinPoint获取参数的值和方法名称
AspectJ使用org.aspectj.lang.JoinPoint接口表示目标类连接点对象,如果是环绕增强时,使用org.aspectj.lang.ProceedingJoinPoint表示连接点 ...
- Spring AOP Example – Advice
Spring AOP + AspectJ Using AspectJ is more flexible and powerful. Spring AOP (Aspect-oriented progra ...
- 使用Spring AOP预处理Controller的参数
实际编程中,可能会有这样一种情况,前台传过来的参数,我们需要一定的处理才能使用,比如有这样一个Controller @Controller public class MatchOddsControll ...
- Spring AOP 中 advice 的四种类型 before after throwing advice around
spring AOP(Aspect-oriented programming) 是用于切面编程,简单的来说:AOP相当于一个拦截器,去拦截一些处理,例如:当一个方法执行的时候,Spring 能够拦截 ...
- Spring AOP增强(Advice)
Sring AOP通过PointCut来指定在那些类的那些方法上织入横切逻辑,通过Advice来指定在切点上具体做什么事情.如方法前做什么,方法后做什么,抛出异常做什么. Spring中有两种方式定义 ...
- Spring AOP获取方法的参数名称和参数值
aop配置: <aop:aspectj-autoproxy expose-proxy="true" /> @Before(value = "execution ...
- Spring Aop 修改目标方法参数和返回值
一.新建注解 @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Document ...
随机推荐
- spark操作Kudu之读 - 使用DataFrame API
虽然我们可以通过上面显示的KuduContext执行大量操作,但我们还可以直接从默认数据源本身调用读/写API. 要设置读取,我们需要为Kudu表指定选项,命名我们要读取的表以及为表提供服务的Kudu ...
- Linux拷贝U盘文件(命令行)
Linux系统有的有界面,有的没有只要命令窗口,因此导入外部文件就变得困难,没有可视化的方便. 这里通过挂载u盘进行文件拷贝. 首先挂载u盘:这里以centos为例 1.进入命令行模式下,输入命令 s ...
- python--异常捕获
#异常捕获---指定异常类型 try: #尝试 fi=open(r'D:\Users\4399-3046\Desktop\test.txt',mode='wb'); fi.write('写入文字'); ...
- Noj - 在线强化训练1
1445 A 求n个整数的和 1564 B 判断一个数是否是完全数 1011 C 判素数(Prime number) 1566 D 输入一组整数,找出最小值 1200 E 判断三角 ...
- 整合django和bootstrap框架
环境: python版本:2.7.8 django版本:1.7.1 bootstrap版本:3.3.0 首先github上面有两个开源的项目用来整合django和bootstrap. https:// ...
- centos6.9安装mysql5.7.18
详细记录在CentOS 6.9上安装MySQL 5.7.18 过程,希望对大家有所帮助. 下载地址:https://dev.mysql.com/get/Downloads/MySQL-5.7/mysq ...
- 打印星星 - Python
打印星星是经典面试题目,考察流程控制中的循环和条件.本文对相关方法进行总结. 到的方法只要有(1)嵌套循环(2)center(3)format(^)(4)字符串乘法 # -*- coding:utf- ...
- Git 日常工作中使用的命令记录
前言 这篇文章主要是介绍我在使用Git中的有一些忘记了,但是很重要的命令. 20190424 Git 历史信息 username 和 email 更改 git config alias.chang ...
- A - Character Encoding HDU - 6397 - 方程整数解-容斥原理
A - Character Encoding HDU - 6397 思路 : 隔板法就是在n个元素间的(n-1)个空中插入k-1个板,可以把n个元素分成k组的方法 普通隔板法 求方程 x+y+z=10 ...
- BZOJ-2-4870: [Shoi2017]组合数问题 矩阵优化 DP
就 是 要 我 们 从 n k 件 物 品 里 面 选 出 若 干 件,使 得 其 数 量 模 k 等 于 r 的 方 案 数 . dp方程 f [ i , j ] 表示前 i 件物品拿了若干件使 ...