目前所有的spring文章一律使用spring 4.2.4,包括前面的三篇
在前一篇中,代码里有一些@PointCut、@Before等的基本应用代码,而这次,我们将一起学习一下aop中的参数绑定、在此之前,我们先定义一个最基本的bean
@Component public class HelloWorld { public void sayHello (Data param){ System.out.println("Hello World! -> " + param.name); } }
在这个bean中、sayHello(Data)即我们要进行aop的方法、它有一个类型为Data的参数、Data也很简单
public class Data { public String name; public Data (String name){ this.name = name; } }
接下来定义切面
@Aspect @Component public class HelloWorldAspect { @Before(value = "execution(* bindData.HelloWorld.sayHello(*)) && args(param2)") private void beforeSayHello (Data param2){ System.out.println("this is before advice! -> " + param2.name); param2.name = "change"; } }
为了能使大家更好的理解、我特意没有将所有的参数均命名为param~~~
首先说明一点、sayHello(Data param)方法的参数名与切面中的args参数名完全没有关系。注意,我说的是参数名,而不是参数类型没关系。
下面我们逐一介绍上面@Before(value = "execution(* bindData.HelloWorld.sayHello(*)) && args(param2)")
@Before:表示前置通知。
value:匹配切点。
execution:声明具体的切点;此处表示取bindData包下HelloWorld类的sayHello方法、sayHello方法有且仅有一个参数,该方法可以返回任意的值。
args:匹配参数;在这里,param2首先匹配beforeSayHello方法中的param2参数,注意,这里是匹配名称相同的参数,然后取得param2的类型,为Data,表示匹配的sayHello(*)方法中的参数类型必须为Data,否则不予匹配。
最后,我们进行测试,当然还是全注解模式:
@Configuration @EnableAspectJAutoProxy @ComponentScan(basePackages = "bindData") public class AopConfig { @Test public void testBeforeSayHello (){ ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class); Data data = new Data("no change"); HelloWorld hw = ctx.getBean(HelloWorld.class); hw.sayHello(data); } }
结果为
this is before advice! -> no change Hello World! -> change
这样一来,我们就能实现在前置通知中改变被切方法的参数值了
还有一点需要注意:
it’s worth pointing out that this won’t work for generic collections. So you cannot define a pointcut like this:
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)") public void beforeSampleMethod(Collection<MyType> param) { // Advice implementation }
意思是不支持范型集合,不要像上面这样使用