Spring Aop Advise方法(增强方法) 中获取目标方法的参数
1. 概念
切面类: 一种特殊bean,通过aop配置,其中的方法(增强方法),会对目标bean的目标方法做一些增强处理
(比如在目标方法之前或之后调用等).
切入点(pointcut): 一种规则,普通bean中符合这种规则的方法,将成为上面切面类中所说的目标方法,接受切面类方法
的特殊处理.
增强方法(Advice),包括aop:befor,aop:after,aop:after-retuing,aop:around,aop:throwing等.
2. 配置片段:
<!-- AOP测试的chinese --> <bean id="chinese_aop" class="test.aop.Chinese" /> <!-- 定义一个普通bean,作为切面bean --> <bean id="accessArgAspect" class="test.aop.aspect.AccessArgAspect" /> <!-- AOP配置 --> <aop:config> <!-- 配置切面aspect --> <aop:aspect id="aspect" ref="accessArgAspect"> <aop:after-returning pointcut="execution(* test.aop.*.*(..))" method="access" returning="retval" arg-names="time,food,retval" /> </aop:aspect> </aop:config>
上面的配置中:
<bean id="chinese_aop" class="test.aop.Chinese" />
配置了普通的bean,该bean中的一些方法
即将满足切入点配置规则,接受切面类中增强方法(Advice)的增强处理.
<bean id="accessArgAspect" class="test.aop.aspect.AccessArgAspect" /> 定义一个切面类,
切面类可以是一个普通的bean.
<aop:config>
<!--配置切面aspect,通过ref关联到前面配置的作为切面类的bean-->
<aop:aspect id="aspect" ref="accessArgAspect">
<!-- 配置一种aop:after-returning增强处理-->
<aop:after-returning
<!-- 切入点 规则,符合这个规则的普通bean中的方法将接受增强处理 -->
pointcut="execution(*test.aop.*.*(..)) and args(food,time,..)"
<!-- 切面类中,作为增强处理的方法的名称 -->
method="access"
<!-- 普通bean,接受增强处理方法的返回值,void的类型被视为null -->
returning="retval"
<!-- 切面类中增强方法的参数名,这个配置可以省略 -->
arg-names="time,food,retval"
/>
</aop:aspect>
</aop:config>
3. 参数绑定
切面类 方法(增强方法)获取 目标方法(普通bean中接受增强方法处理的方法) 参数的方式称为参数绑定.
(1) 增强方法 不需要传递参数,则不需要参数绑定.
(2) 增强方法中,只有一个JoinPoint类型的参数,使用这种参数,也不需要参数绑定.
因为, JoinPoint类有一些方法可以获取目标方法的调用信息(包括参数信息),比如:
Object[] getArgs(),返回在执行目标方法时传递的参数
Signature getSignature(),获取 目标方法的签名
Object getTarget():返回被植入 增强处理的目标对象
Object getThis(): 返回AOP框架为目标对象生成的代理对象(Spring AOP通过动态代理实现)
假如是aop:around类型的增强处理方法,可以使用ProceedingJoinPoint作为参数,
ProceedingJoinPoint除了有上述的几个方法外,还有一个proceed()方法,替代目标方法执行.
(3) 增强方法中,有普通类型的参数,
比如public void access(Date time,String food, String retval)
这种增强方法,必须要在pointcut中通过配置args 和 returning,保证参数正确绑定.
(returning只针对aop:after-returning类型的增强处理,其他的可以省略)
(即,增强方法中出现的参数名必须在pointcut配置中都得到明确的配置,否则报异常)
pointcut="execution(*test.aop.*.*(..)) and args(food,time,..)"
中args(food,time,..)中的food和time是参数名,来自切面类的增强方法,不能乱写,
必须和切面类中增强方法的参数名称一致,在切面类的增强方法参数列表中必须能找到.
因为在增强方法public void access(Date time,String food, String retval)中,time是Date类型的,
food是String类型的,所以pointcut(切入点)定义中and args(food,time,..)符合and前面的规则的同时
还要符合args(food,time,..)的规则.
args(food,time,..)表是所有 第一个参数是String类型,第二个参数是Date类型的方法才能称为目标方法.
.. 表示可以有第三个,第四个, ... , 第n个参数,但是至少有两个参数(String,Date)
所以需要注意的有:
a. 切面类中的增强方法参数,必须要在pointcut中有明确指定,比如
public void access(Date time,String food, String retval)
这个方法中三个参数food,和time通过args指定了,retval表示aop:after-returning定义的目标函数的返回值.
b. 明确指定了参数后,AOP框架在运行时能正确绑定参数,因为:
and args(food,time,..)表示 只对一类目标方法的调用做增强处理,这种目标方法是:在准备调用这种目标方法时,
实际传递给它的参数为food和time所表示的类型(food和time必须在增强方法的参数列表中找到,这样就根据增强方法确定了food和time的类型).
并且,传递参数的顺序也要是和args(food,time,..)中一致.这样在调用目标方法时,至少会按顺序传递food,time两个参数,
AOP框架可以将这两个参数传递给 增强方法.
(4) 增强方法中 有 JoinPoint和普通类型参数,
则必须将JoinPoint类型的参数作为第一个参数,普通参数从第二个开始.
其他的处理方式,按照上面(3)中仅含有普通参数的方式处理.
主要代码;
package test.aop; import java.util.Date; /** * * 普通bean的接口 * */ public interface Person { String sayHello(String name); void eat(String food, Date time); void eat2(String food, Date time,String test); }
package test.aop; import java.util.Date; /** * *一个普通bean,eat方法和sayHello方法,是需要被切入,动态影响的 * */ public class Chinese implements Person { @Override public void eat(String afood, Date atime) { System.out.println("正在吃: " + afood + ", 时间是: " + atime); } @Override public String sayHello(String name) { return name + " Hello, Spring AOP."; } public void eat2(String afood, Date atime,String test) { System.out.println("eat2 --------- 正在吃: " + afood + ", 时间是: " + atime + ", eat2里面的test= " + test); } }
package test.aop.aspect; import java.util.Arrays; import java.util.Date; import org.aspectj.lang.JoinPoint; /** * * 定义切面类,处理test.aop.Chinese.eat() * */ public class AccessArgAspect { //普通的 增强方法 public void access(Date time,String food, String retval) { System.out.println(""); System.out.println("目标方法中 String 参数为: " + food); System.out.println("目标方法中 String 参数为: " + time); System.out.println("目标方法 返回值: " + retval); System.out.println("模拟记录日志..."); } /** * 第一个参数为JoinPoint类型的增强方法,JoinPoint必须为第一个参数 * @param jp * @param time * @param food * @param retval */ public void accessWithJoinPoint(JoinPoint jp,Date time,String food) { System.out.println(""); System.out.println("JoinPoint.getArgs()获取参数列表:" + Arrays.toString(jp.getArgs())); System.out.println("JoinPoint jp ---- 目标方法中 String 参数为: " + food); System.out.println("JoinPoint jp ---- 目标方法中 String 参数为: " + time); System.out.println("JoinPoint jp ---- 模拟记录日志..."); } }
package test.aop; import java.util.Date; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * * AOP客户端测试类 * */ public class TestClient { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); System.out.println(ctx); Person person = ctx.getBean("chinese_aop",Person.class); person.sayHello("jack"); person.eat("米饭",new Date()); person.eat2("米饭",new Date(),"test"); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <!-- 小试牛刀 property使用 name,value--> <bean id="personService" class="test.spring.PersonService"> <property name="name" value="wawa"></property> </bean> <!-- 设值注入 property使用 name,ref , ref也是一个bean的id,ref 可以在stoneAxe和steelAxe之间随意切换,而不用修改java代码 --> <bean id="chinese" class="test.ioc.setter.Chinese"> <property name="axe" ref="steelAxe"></property> </bean> <bean id="stoneAxe" class="test.ioc.setter.StoneAxe" /> <bean id="steelAxe" class="test.ioc.setter.SteelAxe" /> <!-- 构造注入 constructor-arg标签,ref , ref也是一个bean的id,ref 可以在stoneAxe和steelAxe之间随意切换,而不用修改java代码 constructor-arg 也可以配置value,表示传递给构造函数的是一个 普通的值,而不是另一个bean --> <bean id="chinese1" class="test.ioc.constructor.Chinese"> <constructor-arg ref="steelAxe" /> </bean> <!-- 国际化 --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames" > <list> <!-- 这里的value可带路径 --> <value>message</value> </list> </property> </bean> <!-- ApplicationContext的事件机制 在Spring中配置了实现ApplicationListener接口的Bean, Spring容器就会把这个Bean当成容器事件的监听器 --> <bean class="test.springevent.EmainNotifier" /> <!-- bean中获取 ApplicationContext引用--> <bean name="beangetappcontext" class="test.bean.get.appcontext.BeanGetAppContext" /> <!-- AOP测试的chinese --> <bean id="chinese_aop" class="test.aop.Chinese" /> <!-- 定义一个普通bean,作为切面bean --> <bean id="accessArgAspect" class="test.aop.aspect.AccessArgAspect" /> <!-- AOP配置 --> <aop:config> <!-- 配置切面aspect --> <aop:aspect id="aspect" ref="accessArgAspect"> <aop:after-returning pointcut="execution(* test.aop.*.*(..)) and args(food,time,..)" method="access" returning="retval" arg-names="time,food,retval" /> <aop:before pointcut="execution(* test.aop.*.*(..)) and args(food,time,..)" method="accessWithJoinPoint" /> </aop:aspect> </aop:config> </beans>
工程文件注:
使用Spring 3.2.0的所有ja包,
3.2.0的srping包,做AOP需要依赖(Spring 3.2.0中去除了依赖包,需要自己找)
com.springsource.org.aopalliance-1.0.0.jar,下载地址http://ebr.springsource.com/repository/app/bundle/version/detail?name=org.springframework.aop&version=3.2.0.RELEASE
还有,3.0.2的com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar包,
下载3.0.2版本的依赖包以后,找
spring-framework-3.0.2.RELEASE-dependencies (1)\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE这个目录里面有
附件中工程已包含所有需要的jar包
相关推荐
当多个相同的参数调用同一个方法时,后续调用将从缓存中直接获取结果,避免重复计算。实现这一功能的关键在于正确配置Spring容器,创建目标对象的代理,并指定拦截器。 总之,Spring AOP通过代理机制和通知实现横切...
在本篇内容中,我们将深入探讨如何使用配置文件来设置 Spring.NET 的 AOP 功能。 **一、什么是AOP?** 面向切面编程(Aspect-Oriented Programming, AOP)是一种编程范式,旨在解决程序中的横切关注点,如日志记录...
在Spring框架中,Bean注解和AOP(面向切面编程)是两个核心概念,它们在实际开发中扮演着至关重要的角色。让我们深入探讨这两个主题。 首先,我们来看Bean注解。在Spring 4中,注解是配置Bean的主要方式,它提供了...
在"Spring小例子项目源码"中,我们可以深入学习和理解Spring的核心特性,特别是Spring AOP(面向切面编程)和线程管理。下面将详细讲解这两个关键知识点。 **一、Spring AOP** Spring AOP是Spring框架的重要组成...
在 Spring AOP 中,切面主要通过两种方式实现:代理模式(Proxy)和织入(Weaving)。 1. **代理模式**:Spring 提供了两种代理类型——JDK 动态代理和 CGLIB 代理。JDK 代理基于接口实现,适用于那些实现了接口的...
在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许程序员定义横切关注点,如日志、事务管理等,这些关注点可以被编织到应用程序的多个点,而无需侵入核心业务逻辑。Spring的通知(advises)是实现AOP的...
AOP 面向切面的编程思想。 Spring的主要特性之一,今天我整理了一下,小牛试刀,写了一个Demo分享给大家。 切面最主要的功能是在不影响主业务方法逻辑的情况下,在执行业务方法之前或之后加入执行代码。 在JavaEE...
"aspectwerkz"是指AspectWerkz,这是一个开源的AOP(面向切面编程)框架,它允许开发者在Java应用程序中实现切面,以增强代码的模块化和可维护性。"jdk14"表明此版本的AspectWerkz是为Java Development Kit 1.4设计...