Spring中的AOP在Advice方法中获取目标方法的参
参考:http://my.oschina.net/itblog/blog/211693
http://christang.iteye.com/blog/2037919
http://blog.csdn.net/lirui0822/article/details/8555691
http://zywang.iteye.com/blog/974226
获取目标方法的信息
访问目标方法最简单的做法是定义增强处理方法时,将第一个参数定义为JoinPoint类型,当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点。JoinPoint里包含了如下几个常用的方法:
Object[] getArgs:返回目标方法的参数
Signature getSignature:返回目标方法的签名
Object getTarget:返回被织入增强处理的目标对象
Object getThis:返回AOP框架为目标对象生成的代理对象
注意:当使用@Around处理时,我们需要将第一个参数定义为ProceedingJoinPoint类型,该类是JoinPoint的子类。
下面的切面类(依然放在com.abc.advice包中)中定义了Before、Around、AfterReturning和After 4中增强处理,并分别在4种增强处理中访问被织入增强处理的目标方法、目标方法的参数和被织入增强处理的目标对象等:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
package com.abc.advice;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AdviceTest {
@Around ( "execution(* com.abc.service.*.many*(..))" )
public Object process(ProceedingJoinPoint point) throws Throwable {
System.out.println( "@Around:执行目标方法之前..." );
//访问目标方法的参数:
Object[] args = point.getArgs();
if (args != null && args.length > 0 && args[ 0 ].getClass() == String. class ) {
args[ 0 ] = "改变后的参数1" ;
}
//用改变后的参数执行目标方法
Object returnValue = point.proceed(args);
System.out.println( "@Around:执行目标方法之后..." );
System.out.println( "@Around:被织入的目标对象为:" + point.getTarget());
return "原返回值:" + returnValue + ",这是返回结果的后缀" ;
}
@Before ( "execution(* com.abc.service.*.many*(..))" )
public void permissionCheck(JoinPoint point) {
System.out.println( "@Before:模拟权限检查..." );
System.out.println( "@Before:目标方法为:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println( "@Before:参数为:" + Arrays.toString(point.getArgs()));
System.out.println( "@Before:被织入的目标对象为:" + point.getTarget());
}
@AfterReturning (pointcut= "execution(* com.abc.service.*.many*(..))" ,
returning= "returnValue" )
public void log(JoinPoint point, Object returnValue) {
System.out.println( "@AfterReturning:模拟日志记录功能..." );
System.out.println( "@AfterReturning:目标方法为:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println( "@AfterReturning:参数为:" +
Arrays.toString(point.getArgs()));
System.out.println( "@AfterReturning:返回值为:" + returnValue);
System.out.println( "@AfterReturning:被织入的目标对象为:" + point.getTarget());
}
@After ( "execution(* com.abc.service.*.many*(..))" )
public void releaseResource(JoinPoint point) {
System.out.println( "@After:模拟释放资源..." );
System.out.println( "@After:目标方法为:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println( "@After:参数为:" + Arrays.toString(point.getArgs()));
System.out.println( "@After:被织入的目标对象为:" + point.getTarget());
}
}
|
在AdviceManager类中增加以下内容:
1
2
3
4
5
|
//将被AdviceTest的各种方法匹配
public String manyAdvices(String param1, String param2) {
System.out.println( "方法:manyAdvices" );
return param1 + " 、" + param2;
}
|
在com.abc.main.AOPTest中加入方法的调用,触发切点:
1
2
|
String result = manager.manyAdvices( "aa" , "bb" );
System.out.println( "Test方法中调用切点方法的返回值:" + result);
|
下面是执行结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Around :执行目标方法之前...
@Before :模拟权限检查...
@Before :目标方法为:com.abc.service.AdviceManager.manyAdvices
@Before :参数为:[改变后的参数 1 , bb]
@Before :被织入的目标对象为:com.abc.service.AdviceManager @1dfc617e
方法:manyAdvices
@Around :执行目标方法之后...
@Around :被织入的目标对象为:com.abc.service.AdviceManager @1dfc617e
@After :模拟释放资源...
@After :目标方法为:com.abc.service.AdviceManager.manyAdvices
@After :参数为:[改变后的参数 1 , bb]
@After :被织入的目标对象为:com.abc.service.AdviceManager @1dfc617e
@AfterReturning :模拟日志记录功能...
@AfterReturning :目标方法为:com.abc.service.AdviceManager.manyAdvices
@AfterReturning :参数为:[改变后的参数 1 , bb]
@AfterReturning :返回值为:原返回值:改变后的参数 1 、 bb,这是返回结果的后缀
@AfterReturning :被织入的目标对象为:com.abc.service.AdviceManager @1dfc617e
Test方法中调用切点方法的返回值:原返回值:改变后的参数 1 、bb,这是返回结果的后缀
|
从结果中可以看出:在任何一个织入的增强处理中,都可以获取目标方法的信息。另外,Spring AOP采用和AspectJ一样的有限顺序来织入增强处理:在“进入”连接点时,最高优先级的增强处理将先被织入(所以给定的两个Before增强处理中,优先级高的那个会先执行);在“退出”连接点时,最高优先级的增强处理会最后被织入(所以给定的两个After增强处理中,优先级高的那个会后执行)。当不同的切面中的多个增强处理需要在同一个连接点被织入时,Spring AOP将以随机的顺序来织入这些增强处理。如果应用需要指定不同切面类里的增强处理的优先级,Spring提供了如下两种解决方案:
让切面类实现org.springframework.core.Ordered接口:实现该接口只需要实现一个int getOrder()方法,该方法返回值越小,优先级越高
直接使用@Order注解来修饰一个切面类:使用这个注解时可以配置一个int类型的value属性,该属性值越小,优先级越高
优先级高的切面类里的增强处理的优先级总是比优先级低的切面类中的增强处理的优先级高。例如:优先级为1的切面类Bean1包含了@Before,优先级为2的切面类Bean2包含了@Around,虽然@Around优先级高于@Before,但由于Bean1的优先级高于Bean2的优先级,因此Bean1中的@Before先被织入。
同一个切面类里的两个相同类型的增强处理在同一个连接点被织入时,Spring AOP将以随机的顺序来织入这两个增强处理,没有办法指定它们的织入顺序。如果确实需要保证它们以固有的顺序被织入,则可以考虑将多个增强处理压缩为一个增强处理;或者将不同增强处理重构到不同切面中,通过在切面级别上定义顺序。
如果只要访问目标方法的参数,Spring还提供了一种更加简洁的方法:我们可以在程序中使用args来绑定目标方法的参数。如果在一个args表达式中指定了一个或多个参数,该切入点将只匹配具有对应形参的方法,且目标方法的参数值将被传入增强处理方法。下面辅以例子说明:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.abc.advice;
import java.util.Date;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AccessArgAdviceTest {
@AfterReturning (
pointcut= "execution(* com.abc.service.*.access*(..)) && args(time, name)" ,
returning= "returnValue" )
public void access(Date time, Object returnValue, String name) {
System.out.println( "目标方法中的参数String = " + name);
System.out.println( "目标方法中的参数Date = " + time);
System.out.println( "目标方法的返回结果returnValue = " + returnValue);
}
}
|
上面的程序中,定义pointcut时,表达式中增加了args(time, name)部分,意味着可以在增强处理方法(access方法)中定义time和name两个属性——这两个形参的类型可以随意指定,但一旦指定了这两个参数的类型,则这两个形参类型将用于限制该切入点只匹配第一个参数类型为Date,第二个参数类型为name的方法(方法参数个数和类型若有不同均不匹配)。
注意,在定义returning的时候,这个值(即上面的returning="returnValue"中的returnValue)作为增强处理方法的形参时,位置可以随意,即:如果上面access方法的签名可以为
1
|
public void access(Date time, Object returnValue, String name)
|
也可以为
1
|
public void access(Object returnValue, Date time, String name)
|
还可以为
1
|
public void access(Date time, String name, Object returnValue)
|
只需要满足另外的参数名的顺序和pointcut中args(param1, param2)的顺序相同即可。我们在AdviceManager中定义一个方法,该方法的第一个参数为Date类型,第二个参数为String类型,该方法的执行将触发上面的access方法,如下:
1
2
3
4
5
|
//将被AccessArgAdviceTest的access方法匹配
public String accessAdvice(Date d, String n) {
System.out.println( "方法:accessAdvice" );
return "aa" ;
}
|
在AOPTest中增加调用这个accessAdvice方法并执行,下面是输出结果:
从执行结果可以看出,使用args表达式有如下两个作用:
提供了一种简单的方式来访问目标方法的参数
可用于对切入点表达式作额外的限制
除此之外,使用args表达式时,还可以使用如下形式:args(param1, param2, ..),注意args参数中后面的两个点,它表示可以匹配更多参数。在例子args(param1, param2, ..)中,表示目标方法只需匹配前面param1和param2的类型即可。
实现:
//方法执行的前后调用 public Object umpAround(ProceedingJoinPoint point) {Object object = null;WSParameter parameter = null;CallerInfo callerInfo = null;CallerInfo systemCallerInfo = null;try {parameter = (WSParameter) point.getArgs()[0];//添加HTTP调用统一入口UMP监控callerInfo = umpRegisterInfo(UMP_KEY_TOTAL_PREFIX);//渠道来源监控点systemCallerInfo = umpRegisterInfo(UMP_KEY_PREFIX + parameter.getSystemId());object = point.proceed();} catch (Throwable e) {LOG.error("invoke umpAround error,cause:"+e.getMessage()+",paramter="+parameter,e);}finally{//结束渠道来源监控点if(systemCallerInfo != null){umpRegisterInfoEnd(systemCallerInfo);}//HTTP调用统一入口UMP监控结束umpRegisterInfoEnd(callerInfo);}return object; } /*** 在被监控方法的起始位置加入* * @return*/private CallerInfo umpRegisterInfo(String umpKey) {return Profiler.registerInfo(umpPreKey + umpKey, true, true);}/*** 在被监控方法的结束位置加入*/private void umpRegisterInfoEnd(CallerInfo callerInfo) {if (callerInfo != null) {Profiler.registerInfoEnd(callerInfo);}}配置文件:
<bean id="umpAdvice" class="com.yys.ws.mobile.web.saf.UMPInterceptor"/><aop:config> <aop:aspect ref="umpAdvice"> <aop:around method="umpAround" pointcut="execution (* com.yys.ws.mobile.web.ws.YYSTreatyOfferImpl.*(..))"/> </aop:aspect> </aop:config>
第二种:
//添加HTTP调用统一入口UMP监控CallerInfo callerInfo = null;//渠道来源监控点CallerInfo systemCallerInfo = null;public void beforeUMP(JoinPoint jp){WSParameter parameter = null;try {callerInfo = umpRegisterInfo(UMP_KEY_TOTAL_PREFIX);parameter = (WSParameter) jp.getArgs()[0];//添加渠道来源监控点systemCallerInfo = umpRegisterInfo(UMP_KEY_PREFIX + parameter.getSystemId());} catch (Exception e) {LOG.error("invoke beforeUMP error,cause:"+e.getMessage()+",paramter="+parameter,e);}}public void afterUMP(JoinPoint jp){//结束渠道来源监控点if(systemCallerInfo != null){umpRegisterInfoEnd(systemCallerInfo);systemCallerInfo = null;}//HTTP调用统一入口UMP监控结束umpRegisterInfoEnd(callerInfo);callerInfo = null;}配置文件:
<aop:config><aop:aspect id="umpAspect" ref="umpAdvice">切入点<aop:pointcut id="beforePointCut" expression="execution (* com.yys.ws.mobile.web.ws.YYSTreatyOfferImpl.*(..))"/><aop:pointcut id="afterPointCut" expression="execution (* com.yys.ws.mobile.web.ws.YYSTreatyOfferImpl.*(..))"/>织入(通知作用于切入点)<aop:before method="beforeUMP" pointcut-ref="beforePointCut"/><aop:after method="afterUMP" pointcut-ref="afterPointCut"/></aop:aspect></aop:config>
Spring中的AOP在Advice方法中获取目标方法的参相关推荐
- Spring中的AOP——在Advice方法中获取目标方法的参数(转)
获取目标方法的信息 访问目标方法最简单的做法是定义增强处理方法时,将第一个参数定义为JoinPoint类型,当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点.JoinPo ...
- java获取方法上的注解_Spring:使用Spring AOP时,如何获取目标方法上的注解
当使用spring AOP时,判断目标方法上的注解进行相关操作,如缓存,认证权限等 自定义注解 packagecom.agent.annotation;importjava.lang.annotati ...
- 网页中Flash播放器里的视频获取的方法
但最老是有网友问我网站Flash播放器所播出的视频怎么下?所以决定把聊天记录整理一下,写成blog. Flash播放器所支持的视频文件格式为FLV,如果需要在本机播放FLV文件,需要下载专门的播放器, ...
- Aspect获取目标方法中带特定注解的参数值
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {Method method = ((MethodSignature) ...
- java 获取方法的注释_java – 有更有效的方法来获取注释方法吗?
看看 Reflections(依赖: Guava和 Javassist).这是一个已经优化了这一切的图书馆.有一个 Reflections#getMethodsAnnotatedWith()适合您的功 ...
- 一文读懂Spring中的AOP机制
一.前言 这一篇我们来说一下 Spring 中的 AOP 机制,为啥说完注解的原理然后又要说 AOP 机制呢? 1.标记日志打印的自定义注解 @Target({ElementType.METHOD}) ...
- Spring框架(中) AOP
Spring(中) AOP (一)代理模式 1.静态代理 静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类. 举例: package co ...
- 深入理解spring中的AOP原理——实现MethodInterceptor接口,自已动手写一个AOP
1.前言 AOP是面向切面编程,即"Aspect Oriented Programming"的缩写.面对切面,就是面向我们的关注面,不能让非关注面影响到我们的关注面.而现实中非关切 ...
- java学习day40(Spring)spring中的aop和基于XML以及注解的AOP配置
第1章 AOP 的相关概念[理解] 1.1AOP 概述 1.1.1 什么是 AOP AOP :全称是 Aspect Oriented Programming 即:面向切面编程. 简单的说它就是把我们程 ...
最新文章
- 全民K歌内容挖掘与召回
- python 递归目录_Python3:递归实现输出目录下所有的文件
- Zookeeper知识点详解
- Windows phone 8 学习笔记(4) 应用的启动
- maven工程建立和SSM(springMVC+spring+mybatis)整合
- tornado学习笔记day02-进阶与提升
- 年薪50万,他们招180名博士
- MySQL 5.7原生JSON格式支持
- allergo 导出光辉配置_请教Allegro导出光绘文件的层要选择哪些层?
- spring boot 事务_Redis 事务在 SpringBoot 中的应用
- Ubuntu gitweb 安装配置
- 相机标定后图像像素和物理尺寸对应_你需要事件相机标定板,咱做了个
- 转:zTree树控件入门之checkbox:如何动态设置节点的checkbox选择框启用与禁用状态(chkDisabled)...
- 数据库常见面试题(附答案)
- 在静止状态下根据IMU(加速度计)计算姿态角
- 使用Electron将html网页转为exe可执行文件(全屏, 遮住任务栏, Esc退出, exe的图标/文件名修改)
- 四相八拍步进c语言程序,四相八拍的步进电机简单的驱动
- eNSP不同网段主机互联-static
- 【Python】Python 函数用法:str()、int()、float() 函数
- php 实现抽奖接口,PHP转盘抽奖接口实例
热门文章
- linux操作系统学习网站整理(100个)
- [DefaultProperty(Text),ToolboxData()]
- [翻译]一步步教你配置SQL SERVER合并复制(五)配置Publisher(上)
- java二维对象数组存入文件_关于Java:将2D数组保存到磁盘文件
- python中id3决策树算法_ID3决策树算法实现(Python版)
- python求三角形面积步骤_python算三角形面积
- 设计模式 — 结构型模式 — 组合模式
- MySQL — 外键关联操作
- ARM中char、short、int、long、float、double数据类型占多少位
- stm32 TIM2 重映射