上一篇文章讲的是springaop的最基本配置,没有任何参数,有参数的也就在环绕通知@Around
中使用了ProceedingJoinPoint
作为参数,要是切面所通知的方法确实有参数该怎么办?下面通过一个需求来实现aop处理参数的功能。
需求
一个马戏团里有很多演员,编号分别为A、B、C…,老板要记录每个演员的演出次数作为年底发红包的依据。
如果我们让演员去记录自己的演出次数,是可以的,但是你防不了一些歪心眼的演员故意提高自己的演出次数或者有时候演出太着急就会漏记次数。所以这里我们可以让老板聘请一位专门记录演员演出次数的“记录员”这样就绝对不会出错了。
接下来我们用springAOP来实现这一需求,同样,本文给出两种写法注解式和xml配置的方式。
注解
重写接口
接上文,我们在Performance
里添加一个方法plackTrack(String number)
代码如下
package com.springinaction.service;
public interface Performance {
public void perform();
public void plackTrack(String number);
}
注意,这里包含参数number
为演员的编号。
实现接口
这里依然使用Actor
来实现接口,如下
package com.springinaction.service;
import org.springframework.stereotype.Component;
@Component
public class Actor implements Performance {
@Override
public void perform() {
System.out.println("表演中...");
}
@Override
public void plackTrack(String number) {
System.out.println(number + " number actor");
}
}
编写参数切面
package com.springinaction.aop;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class TrackCountAnnotation {
private Map<String,Integer> trackCounts = new HashMap<String,Integer>();
@Pointcut("execution(** com.springinaction.service.Performance.plackTrack(String)) && args(trackNumber)")
public void trackPlayed(String trackNumber){}
@Before("trackPlayed(trackNumber)")
public void countTrack(String trackNumber){
System.out.println("i am record..." + trackNumber + " people");
int currentCount = getPlayCount(trackNumber);
trackCounts.put(trackNumber, ++currentCount);
}
public int getPlayCount(String trackNumber) {
return trackCounts.get(trackNumber)!=null?trackCounts.get(trackNumber):0;
}
}
这里注意切点表达式,
比普通的aop多了参数的类型和参数名,这里定义了Map<String,Integer>
来存演员的编号和对应的演出次数,这边就只加了一个@Before
的注解,意思就是演员在演出之前将其次数加一,没有对演出失败或者其他意外的情况做处理,可以使用@AfterReturning
和 @AfterThrowing
处理。
编写测试类
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.springinaction.aop.TrackCountAnnotation;
import com.springinaction.service.Actor;
public class ShowTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop-annotation.xml");
Actor actor = (Actor)context.getBean("actor");
TrackCountAnnotation tc = (TrackCountAnnotation) context.getBean("trackCountAnnotation");
actor.plackTrack("A");
actor.plackTrack("B");
actor.plackTrack("B");
actor.plackTrack("C");
actor.plackTrack("C");
actor.plackTrack("C");
actor.plackTrack("D");
actor.plackTrack("D");
System.out.println("A------> " + tc.getPlayCount("A"));
System.out.println("B------> " + tc.getPlayCount("B"));
System.out.println("C------> " + tc.getPlayCount("C"));
System.out.println("D------> " + tc.getPlayCount("D"));
System.out.println("E------> " + tc.getPlayCount("E"));
System.out.println("F------> " + tc.getPlayCount("F"));
System.out.println("G------> " + tc.getPlayCount("G"));
}
}
输出为
i am record...A people
A number actor
i am record...B people
B number actor
i am record...B people
B number actor
i am record...C people
C number actor
i am record...C people
C number actor
i am record...C people
C number actor
i am record...D people
D number actor
i am record...D people
D number actor
A------> 1
B------> 2
C------> 3
D------> 2
E------> 0
F------> 0
G------> 0
这样就通过注解的方式来实现开头的需求,下面是xml配置。
XML配置
XML文件
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<bean id="oldClown" class="com.springinaction.service.OldClown" />
<bean id="trackCountXml" class="com.springinaction.aop.TrackCountXml" />
<aop:aspectj-autoproxy proxy-target-class="true" />
<aop:config>
<aop:aspect id="aspect" ref="trackCountXml">
<aop:pointcut
expression="execution(** com.springinaction.service.Performance.plackTrack(String)) and args(trackNumber)"
id="trackPlayed" />
<aop:before method="countTrack" pointcut-ref="trackPlayed" />
</aop:aspect>
</aop:config>
</beans>
这里需注意xml文件中切点表达式的写法,&&
要使用and
代替。
编写参数切面
package com.springinaction.aop;
import java.util.HashMap;
import java.util.Map;
public class TrackCountXml {
private Map<String,Integer> trackCounts = new HashMap<String,Integer>();
public void trackPlayed(String trackNumber){}
public void countTrack(String trackNumber){
System.out.println("i am record..." + trackNumber + " people");
int currentCount = getPlayCount(trackNumber);
trackCounts.put(trackNumber, ++currentCount);
}
public int getPlayCount(String trackNumber) {
return trackCounts.get(trackNumber)!=null?trackCounts.get(trackNumber):0;
}
}
编写测试类
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.springinaction.aop.TrackCountXml;
import com.springinaction.service.OldClown;
public class ShowTestXml {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop-arg-xml.xml");
// OldClown oldClown = (OldClown)context.getBean("oldClown");// TODO
// // http://www.cnblogs.com/liuling/p/2014-8-23-001.html
// oldClown.perform();
OldClown oldClown = (OldClown)context.getBean("oldClown");
TrackCountXml tc = (TrackCountXml) context.getBean("trackCountXml");
oldClown.plackTrack("A");
oldClown.plackTrack("B");
oldClown.plackTrack("B");
oldClown.plackTrack("C");
oldClown.plackTrack("C");
oldClown.plackTrack("C");
oldClown.plackTrack("D");
oldClown.plackTrack("D");
System.out.println("A------> " + tc.getPlayCount("A"));
System.out.println("B------> " + tc.getPlayCount("B"));
System.out.println("C------> " + tc.getPlayCount("C"));
System.out.println("D------> " + tc.getPlayCount("D"));
System.out.println("E------> " + tc.getPlayCount("E"));
System.out.println("F------> " + tc.getPlayCount("F"));
System.out.println("G------> " + tc.getPlayCount("G"));
}
}
输出的结果和上面是一样的。
因为项目很小就没有放到Git上托管,下面将文件下载地址。