4.4.3 为通知传递参数

在 4.3.3 小节中,我们使用 @AspectJ 注解创建了一个切面,这个切面能够记录 CompactDisc 上每个磁道播放的次数。现在,我们使用 XML 来配置切面,那就看一下如何完成这一相同的任务。

首先,我们要移除掉 TrackCounter 上所有的 @AspectJ 注解。

程序清单 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 声明为切面。唯一明显的差别在于切点表达式中包含了一个参数,这个参数会传递到通知方法中。

我们通过练习已经使用 Spring 的 aop 命名空间声明了几个基本的切面,那么现在让我们看一下如何使用 aop 命名空间声明引入切面。

Last updated