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处理方法,那么我们可以如下这样定义。

1 @Before(value="bean(userService) && execution(* findById(java.lang.Integer)) && args(id)", argNames="id")
2 public void beforeWithParam(JoinPoint joinPoint, Integer id) {
3     System.out.println(this.getClass().getName()+" ID is : " + id);
4 }

上面这种定义是非常精确的定义,我们通过表达式“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参数的方法,那么我们可以把上面的配置简化为如下这样。

1 @Before(value="bean(userService) && args(id)", argNames="id")
2 public void beforeWithParam2(int id) {
3      System.out.println(this.getClass().getName()+" ID is : " + id);
4 }

如果我们需要拦截的方法可能是有多个参数的,但我们只关注第一个参数,那我们可以把表达式调整为如下这样,只关注第一个参数为int/Integer类型的,并且在Advice方法中接收这个方法参数进行相应的处理。

1 @Before(value="bean(userService) && args(id,..)", argNames="id")
2 public void beforeWithParam2(int id) {
3      System.out.println(this.getClass().getName()+" ID is : " + id);
4 }

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放第二位。

1 @Before(value="bean(userService) && args(name, sex)", argNames="sex, name")
2 public void beforeWithParam3(int sex1, String name1) {
3     System.out.println("sex is : " + sex1);
4     System.out.println("name is : " + name1);
5 }

@Before注解的argNames参数不是必须的,它只有在我们编译的字节码中不含DEBUG信息或Pointcut表达式中使用的参数名与Advice处理方法的参数名不一致时才需要。所以在编译的字节码中包含DEBUG信息且Advice参数名与Pointcut表达式中使用的参数名一致时,我们完全可以把argNames参数省略。如果表达式里面使用了多个参数,那么这些参数在表达式中的顺序可以与Advice方法对应参数的顺序不一致,例如下面这个样子。

1 @Before(value="bean(userService) && args(id)")
2 public void beforeWithParam2(int id) {
3     System.out.println(this.getClass().getName()+" ID is : " + id);
4 }

5.3 获取this对象

this对象就是Spring生成的bean的那个代理对象。如下示例就是Advice方法接收this对象,我们给Advice方法指定一个需要拦截的this对象类型的参数,然后在表达式中使用this类型的表达式定义,表达式中定义的对应类型指定为Advice方法参数。

1 @Before("this(userService)")
2 public void beforeWithParam4(IUserService userService) {
3        //this对象应该是一个代理对象
4        System.out.println(this.getClass().getName()+"==============传递this对 
5         象: " + userService.getClass());
6 }

5.4 混合使用

我们的Advice方法可以同时接收多个目标方法参数,与此同时它也可以接收this等对象,即它们是可以混合使用的。下面这个示例中我们就同时接收了this对象和目标方法int/Interger类型的参数。

1 @Before("this(userService) && args(id)")
2 public void beforeWithParam5(IUserService userService, int id) {
3        System.out.println(this.getClass().getName()+"===========" + id + 
4        "==============" + userService.getClass());
5 }

5.5 获取target对象

获取target对象也比较简单,只需要把表达式改为target类型的表达式即可。

1 @Before("target(userService)")
2 public void beforeWithParam6(IUserService userService) {
3        System.out.println(this.getClass().getName()+"==============传递 
4         target对象: " + userService.getClass());
5 }

5.6 获取注解对象

当我们的Pointcut表达式类型是通过注解匹配时,我们也可以在Advice处理方法中获取匹配的注解对象,如下面这个示例,其它如使用@target等是类似的。

1 @Before("@annotation(annotation)")
2 public void beforeWithParam7(MyAnnotation annotation) {
3        System.out.println(this.getClass().getName()+"==============传递标 
4        注在方法上的annotation: " + annotation.annotationType().getName());
5 }

5.7 泛型参数

有的时候我们的Advice方法需要接收的切入点方法参数定义的不是具体的类型,而是一个泛型,这种情况下怎么办呢?可能你会想那我就把对应的Advice方法参数定义为Object类型就好了,反正所有的类型都可以转换为Object类型。对的,这样是没有错的,但是说如果你只想拦截某种具体类型的参数调用时就可以不用把Advice方法参数类型定义为Object了,这样还得在方法体里面进行判断,我们可以直接把Advice方法参数类型定义为我们想拦截的方法参数类型。比如我们有下面这样一个使用了泛型的方法定义,我们希望只有在调用testParam方法时传递的参数类型是Integer类型时才进行拦截。

1 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。

1 @Before("execution(void testParam(..)) && args(param)")
2 public void beforeWithParam8(Integer param) {
3        System.out.println("pointcut expression[args(param)]--------------param:" + 
4        param);
5 }

以上就是常用的传递参数给Advice处理方法的方式,有一些示例可能没有讲到,比如@target这种,这些其实都是类似的。包括上面我们都是以@Before这种Advice来讲的,其实其它的Advice在接收参数的时候也是类似的。

 

转载于:https://www.cnblogs.com/fnlingnzb-learner/p/10716049.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/425079.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第三十五期:AI核心难点之一:情感分析的常见类型与挑战

情感分析或情感人工智能&#xff0c;在商业应用中通常被称为意见挖掘&#xff0c;是自然语言处理(NLP)的一个非常流行的应用。文本处理是该技术最大的分支&#xff0c;但并不是唯一的分支。情绪AI有三种类型及其组合。 情感分析或情感人工智能&#xff0c;在商业应用中通常被称…

AtCoder - 4172 Modulo Summation 贪心

开始想复杂的了 仔细观察样例后发现这个数 其实就是所有的数的LCM-1吗 只有LCM-1 对所有数取模的时候才能对所有数得到MOD = a[i]-1; 那么一个X%Y得到的最大值就是Y-1 于是得到了这个代码 #include<iostream> #include<cstdio> #include<queue> #includ…

[Leetcode][第104题][JAVA][二叉树的最大深度][递归][BFS]

【问题描述】[简单] 【解答思路】 1. 递归 终止条件/基本情况 root null 递推关系 max(l,r)1 时间复杂度&#xff1a;O(N) 空间复杂度&#xff1a;O(height) class Solution {public int maxDepth(TreeNode root) {if (root null) {return 0;} else {int leftHeight ma…

第三十六期:人工智能统计调查:86%的消费者更喜欢人工客服

美国消费者越来越不愿意与聊天机器人聊天&#xff0c;人们对人工智能作为关键业务组成部分的期望越来越高&#xff0c;由于部署这项新技术导致员工技能差距越来越大。 最近一些人工智能的健康和进展状况相关调查、研究、预测和其他定量评估突显出以下几点&#xff1a;美国消费者…

[Leetcode][第111题][JAVA][BFS][二叉树的最小深度][BFS][递归]

【问题描述】[简单] 【解答思路】 1. 递归 自下而上 基本情况/结束条件 &#xff1a; 叶子节点的定义是左孩子和右孩子都为 null 时叫做叶子节点 当 root 节点左右孩子都为空时&#xff0c;返回 1 当 root 节点左右孩子有一个为空时&#xff0c;返回不为空的孩子节点的深度 当…

PAT 1009 说反话

#include<cstdio>#include<cstring>#include<iostream>using namespace std;typedef long long ll;char a[82][82];int cnt;int main(){while(scanf("%s",a[cnt])!EOF){cnt;//***** 由于这里把cnt放到上面的判断中去了导致 最后在判断EOF的时候多判…

75 jsp基础语法汇总

JSP语法 脚本程序 脚本程序可以包含任意量量的Java语句句、变量量、⽅方法或表达式&#xff0c;只要它们在脚本语⾔言 中是有效的。 脚本程序的语法格式&#xff1a; <% 代码⽚片段 %>或者&#xff0c;您也可以编写与其等价的XML语句句&#xff0c;就像下⾯面这样&#…

CodeVS 1300 文字排版 线性DP

1300 文件排版 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description 写电子邮件是有趣的&#xff0c;但不幸的是经常写不好看&#xff0c;主要是因为所有的行不一样长&#xff0c;你的上司想要发排版精美的电子邮件&#xff0c;你的任务是为他编写一个电子邮件排版程序…

[递归]一文看懂递归

1. 递归的定义 编程语言中&#xff0c;函数 Func(Type a,……) 直接或间接调用函数本身&#xff0c;则该函数称为「递归函数」。 在实现递归函数之前&#xff0c;有两件重要的事情需要弄清楚: 递推关系&#xff1a;一个问题的结果与其子问题的结果之间的关系。基本情况&…

centos6.8 安装软件

1.安装jdk1.8 https://blog.csdn.net/zhengjinyou/article/details/80890893 2.安装tomcat8.5 https://www.cnblogs.com/jimboi/p/6405136.html 3.安装nginx https://www.cnblogs.com/vurtne-lu/p/7010065.html nginx: unrecognized service问题解决 https://blog.csdn.ne…

随机

随机数发生器 线性同余 x(i1)Axi%Mx0需要指定&#xff0c;称为种子。如果M11&#xff0c;A7&#xff0c;x01&#xff0c;那么所生成的数为7,5,2,3,10,4,6,9,8,1,7,5,2… 这个序列的周期为M-1。如果M231−1&#xff0c;这个周期应该对大多数应用来说应该够了。

Serval and Parenthesis Sequence CodeForces - 1153C 贪心

题意&#xff1a;给出一个由"(",")","?"三种字符构成的序列&#xff0c;让我们把其中的问号替换成左右括号&#xff0c;使得整个序列变成一个完整地括号序列&#xff0c;也就是括号匹配正确&#xff0c;而且要求不能提前结束的括号序列&#xf…

[Leetcode][第206题][JAVA][反转一个单链表][递归][迭代]

【问题描述】[简单] 【解答思路】 1. 递归 自底向上 基本条件/终止条件&#xff1a;当前节点或者下一个节点null 递推关系&#xff1a; head.next.next head 在函数内部&#xff0c;改变节点的指向&#xff0c;也就是 head 的下一个节点指向 head 递归函数那句 时间…

3.项目的基本概念

项目的基本概念 项目及其特征

python之各种装饰器的使用

"""    装饰器&#xff0c;带参数的装饰器&#xff0c;类的装饰器    判断是否为可迭代的    from collections import Iterable    print(isinstance([1,2,3],Iterable))    """    # 1、简单的装饰器    def debu…

[剑指offer]面试题第[1]题[JAVA][二维数组中的查找][数组][二分]

【问题描述】 在一个二维数组中&#xff08;每个一维数组的长度相同&#xff09;&#xff0c;每一行都按照从左到右递增的顺序排序&#xff0c;每一列都按照从上到下递增的顺序排序。请完成一个函数&#xff0c;输入这样的一个二维数组和一个整数&#xff0c;判断数组中是否含…

[CodeForces-1138B] *Circus 解方程|数学

题意&#xff1a;有两场表演&#xff0c;n个艺术家&#xff0c;根据规则找出我们要挑选的人的编号&#xff0c;输出编号。 规则1 保证每个人只能参加一场表演&#xff0c;也就是同一个艺术家不能出现在两场表演中 规则2 两场表演参演的艺术家的数量是相同的 规则3 第一场可以…