在 4.3.3 小节中,我们使用 @AspectJ 注解创建了一个切面,这个切面能够记录 CompactDisc 上每个磁道播放的次数。现在,我们使用 XML 来配置切面,那就看一下如何完成这一相同的任务。
程序清单 4.13 无注解的 TrackCounter
package soundsystem;
import java.util.HashMap;
import java.util.Map;
public class TrackCounter {
private Map<Integer, Integer> trackCounts = new HashMap<>();
public void trackPlayed(int trackNumber) { }
public void countTrack(int trackNumber) {
int currentCount = getPlayCount(trackNumber);
trackCounts.put(trackNumber, currentCount + 1);
}
public int getPlayCount(int trackNumber) {
return trackCounts.containsKey(trackNumber) ? trackCounts.get(trackNumber) : 0;
}
}
去掉 @AspectJ 注解后,TrackCounter 显得有些单薄了。现在,除非显式调用 countTrack() 方法,否则 TrackCounter 不会记录磁道播放的数量。但是,借助一点 Spring XML 配置,我们能够让 TrackCounter 重新变为切面。
如下的程序清单展现了完整的 Spring 配置,在这个配置中声明了 TrackCounter bean 和 BlankDisc bean,并将 TrackCounter 转化为切面。
程序清单 4.14 在 XML 中将 TrackCounter 配置为参数化的切面
<?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"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd" >
<bean id="trackCounter" class="soundsystem.TrackCounter" />
<bean id="cd" class="soundsystem.BlackDisc" >
<property name="title" value="Sgt. Pepper's Lonelt Hearts Club Band" />
<property name="artist" value="The Beatles" />
<property name="tracks" >
<list>
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>Lucy in the Sky with Diamonds</value>
<value>Getting Better</value>
<value>Fixing a Hole</value>
<!-- ...other tracks omitted for brevity... -->
</list>
</property>
</bean>
<aop:config>
<aop:aspect ref="trackCounter">
<aop:pointcut
id="trackPlayed"
expression="execution(* soundsystem.CompactDisc.playTrack(int)) and args(trackNumber)" />
<aop:before pointcut-ref="trackPlayed" method="countTrack" />
</aop:aspect>
</aop:config>
</beans>
可以看到,我们使用了和前面相同的 aop 命名空间 XML 元素,它们会将 POJO 声明为切面。唯一明显的差别在于切点表达式中包含了一个参数,这个参数会传递到通知方法中。