技术开发 频道

Spring AOP: Spring之面向方面编程

让我们看看Spring如何处理切入点这个重要的概念。

概念
Spring的切入点模型能够使切入点独立于通知类型被重用。 同样的切入点有可能接受不同的 通知。

org.springframework.aop.Pointcut 接口是重要的接口, 用来指定通知到特定的类和方法目标。完整的接口定义如下:

public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher(); }


将Pointcut接口分成两个部分有利于重用类和方法的匹配部分,并且组合细粒度的 操作(如和另一个方法匹配器执行一个”并“的操作)。

ClassFilter接口被用来将切入点限制到一个给定的目标类的集合。 如果matches()永远返回true,所有的目标类都将被匹配。

public interface ClassFilter { boolean matches(Class clazz); } MethodMatcher接口通常更加重要。完整的接口如下: public interface MethodMatcher { boolean matches(Method m, Class targetClass); boolean isRuntime(); boolean matches(Method m, Class targetClass, Object[] args); }

 matches(Method, Class) 方法被用来测试这个切入点是否匹 配目标类的给定方法。这个测试可以在AOP代理创建的时候执行,避免在所有方法调用时都需要进行 测试。如果2个参数的匹配方法对某个方法返回true,并且MethodMatcher的 isRuntime()也返回true,那么3个参数的匹配方法将在每次方法调用的时候被调用。这使 切入点能够在目标通知被执行之前立即查看传递给方法调用的参数。

大部分MethodMatcher都是静态的,意味着isRuntime()方法 返回false。这种情况下3个参数的匹配方法永远不会被调用。

如果可能,尽量使切入点是静态的,使当AOP代理被创建时,AOP框架能够缓存切入点的 测试结果。
切入点的运算
Spring支持的切入点的运算有: 值得注意的是 并 和 交。

并表示只要任何一个切入点匹配的方法。

交表示两个切入点都要匹配的方法。

并通常比较有用。

切入点可以用org.springframework.aop.support.Pointcuts 类的静态方法来组合,或者使用同一个包中的ComposablePointcut类。

实用切入点实现
Spring提供几个实用的切入点实现。一些可以直接使用。另一些需要子类化来实现应用相 关的切入点。

静态切入点
静态切入点只基于方法和目标类,而不考虑方法的参数。静态切入点足够满足大多数情况 的使用。Spring可以只在方法第一次被调用的时候计算静态切入点,不需要在每次方法调用 的时候计算。

让我们看一下Spring提供的一些静态切入点的实现。

正则表达式切入点
一个很显然的指定静态切入点的方法是正则表达式。除了Spring以外,其它的AOP框架也实 现了这一点。org.springframework.aop.support.RegexpMethodPointcut 是一个通用的正则表达式切入点,它使用Perl 5的正则表达式的语法。

使用这个类你可以定义一个模式的列表。如果任何一个匹配,那个切入点将被计算成 true。(所以结果相当于是这些切入点的并集)。

用法如下:

<bean id="settersAndAbsquatulatePointcut" class="org.springframework.aop.support.RegexpMethodPointcut"> <property name="patterns"> <list> <value>.*get.*</value> <value>.*absquatulate</value> </list> </property> </bean>

RegexpMethodPointcut一个实用子类, RegexpMethodPointcutAdvisor, 允许我们同时引用一个通知。 (记住通知可以是拦截器,before通知,throws通知等等。)这简化了bean的装配,因为一个bean 可以同时当作切入点和通知,如下所示:

<bean id="settersAndAbsquatulateAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="interceptor"> <ref local="beanNameOfAopAllianceInterceptor"/> </property> <property name="patterns"> <list> <value>.*get.*</value> <value>.*absquatulate</value> </list> </property> </bean>

 RegexpMethodPointcutAdvisor可以用于任何通知类型。

RegexpMethodPointcut类需要Jakarta ORO正则表达式包。
属性驱动的切入点
一类重要的静态切入点是元数据驱动的 切入点。 它使用元数据属性的值:典型地,使用源代码级元数据。

动态切入点
动态切入点的演算代价比静态切入点高的多。它们不仅考虑静态信息,还要考虑方法的 参数。这意味着它们必须在每次方法调用的时候都被计算;并且不能缓存结果 ,因为参数是变化的。

这个主要的例子就是控制流切入点。

控制流切入点
Spring的控制流切入点概念上和AspectJ的cflow 切入点一致,虽然没有其那么强大(当前没有办法指定一个切入点在另一个切入点后执行)。 一个控制流切入点匹配当前的调用栈。例如,连接点被 com.mycompany.web包或者 SomeCaller类中一个方法调用的时候,触发该切入点。控制流切入点的实现类是 org.springframework.aop.support.ControlFlowPointcut。

注意
控制流切入点是动态切入点中计算代价最高的。Java 1.4中, 它的运行开销是其他动态切入点的5倍。在Java 1.3中则超过10倍。


切入点超类
Spring提供非常实用的切入点的超类帮助你实现你自己的切入点。

因为静态切入点非常实用,你很可能子类化StaticMethodMatcherPointcut,如下所示。 这只需要实现一个抽象方法(虽然可以改写其它的方法来自定义行为)。

class TestStaticPointcut extends StaticMethodMatcherPointcut { public boolean matches(Method m, Class targetClass) { // return true if custom criteria match } }

当然也有动态切入点的超类。

Spring 1.0 RC2或以上版本,自定义切入点可以用于任何类型的通知。

自定义切入点
因为Spring中的切入点是Java类,而不是语言特性(如AspectJ),因此可以定义自定义切入点, 无论静态还是动态。但是,没有直接支持用AspectJ语法书写的复杂的切入点表达式。不过, Spring的自定义切入点也可以任意的复杂。

后续版本的Spring可能象JA一样C提供”语义切入点“的支持:例如,“所有更改目标对象 实例变量的方法”。

0
相关文章