Spring AOP 二代
在 Spring AOP 第一代中, AOP 的 Advice 必须实现特定接口,而配置设置依赖于 XML 的繁琐设置。在 Spring2.0 之后,对于 AOP 功能的实现与设置新增了两种方法:一种是基于 XML Schema 的设置;一种是基于 Annotation 的支持。两种方式对于 AOP 在使用上的简化都有极大地帮助。而且 Advice 不用再实现任何其他特定的接口。
基于XML Schema的前置通知
在这里以实际的例子说明 Spring2.x 在 AOP 的实现和设置上的改变,现在 LogBeforeAdvice 不需要实现 MethodBeforeAdvice ,改写后的程序如下。
public class LogBeforeAdvice {
public void before(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName()+",start.............LogBeforeAdvice");
}
}
在程序代码中, before() 方法为任意取的名称,它可以接受 JoinPoint 实例,也可以省略。可以使用 JoinPoint 的 getTarget() 方法取得目标对象,使用 getArgs() 取得调用的方法参数、使用 getSinature() 方法取得 Pointcut 签名等信息。在 Spring2.x 任何一个 Advice 的方法实现都可以自行决定是否接受 JoinPoint 实例。
<bean id="logBeforeAdvice" class="com.edu.cug.LogBeforeAdvice"/>
<aop:config>
<aop:aspect id="logBeforeAspect" ref="logBeforeAdvice">
<aop:pointcut id="LogbeforePointcut" expression="execution(* hello*(..))"/>
<aop:before pointcut-ref="LogbeforePointcut" method="before"/>
</aop:aspect>
</aop:config>
透过配置文件可以看到,首先不再需要明确声明使用 ProxyFactoryBean ,所有的 AOP 配置都是在 < aop:config > 标签中设置的; < aop:aspect > 标签定义 Aspect 的实现,也就是 Advice 和 Pointcut 结合。
测试程序如下面所示:
public class AopTest {
public static void main(String[] args) {
BeanFactory factory = new ClassPathXmlApplicationContext(
"applicationContext.xml");
IHello bean = (IHello) factory.getBean("IHello");
bean.hello1("AOP1");
bean.hello2("AOP2");
}
}
测试结果如下:
hello1,start.............LogBeforeAdvice
hello1,AOP1
hello2,start.............LogBeforeAdvice
hello2,AOP2
基于Annotation的前置通知
在 Spring2.0 以后,还可以通过 Annotation 来设置 AOP 的 Advice ,在 XML 的设置上可以更加简化,这里改写 LogBeforeAdvice :
@Aspect
public class LogBeforeAdvice {
@Pointcut("execution(* com.edu.cug.IHello.*(..)) ")
public void anymethod(){}
@Before("anymethod()")
public void before(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName()
+ ",start.............LogBeforeAdvice");
}
}
配置文件修改如下:
<bean id="IHello" class="com.edu.cug.IHelloImpl"></bean> <bean id="logBeforeAdvice" class="com.edu.cug.LogBeforeAdvice"></bean> <aop:aspectj-autoproxy/>
测试程序如下:
public class AopTest {
public static void main(String[] args) {
BeanFactory factory = new ClassPathXmlApplicationContext(
"applicationContext.xml");
IHello bean = (IHello) factory.getBean("IHello");
bean.hello1("AOP1");
bean.hello2("AOP2");
}
}
运行结果如下:
hello1,start.............LogBeforeAdvice
hello1,AOP1
hello2,start.............LogBeforeAdvice
hello2,AOP2
可以看到,基于 Annotation 的 AOP 设置方式,在 XML 上几乎不用设置,只要实例化 Advice 与你的目标对象,接着一切就让 Spring 自动取得 Annotation 信息,进行代理对象建立,无须再做任何的设置。这个范例的执行结果和上一个范例是相同的。
Spring的Pointcut定义
在 Spring2.x 中要声明 Pointcut ,主要包括两个部分: Pointcut 表达式 (expression) 与 Pointcut 签名 (signature) 。首先来看 Pointcut 表达式,在 Spring 中, execution 表示式会是最常用的 Pointcut 表示式,它的语法组成格式如下所示:
Execution (modifiers –patterns?
ret-type-pattern
declaring-type-pattern?
name-pattern (param-pattern)
throws-pattern?
)
它们分别表示存取修饰匹配 (modifiers –patterns) 、返回值类型匹配 (ret-type-pattern
) 、类限定名匹配 (declaring-type-pattern) 、方法名称匹配 ( 参数类型匹配 ) 、异常类型匹配 (throws-pattern) 、有问号的部分,表示可以省略不声明。
在 Spring2.x 中,结合 @Pointcut 的 Annotation 定义方式,可以让 Pointcut 在定义上更加容易,定义包含两个部分: Pointcut 表示式与 Pointcut 签名 (signature) 。
Pointcut 定义是,还可以使用 && 、 || 、 ! 运算。
使用 Spring2.x 的新特性实现 AOP 更加简单、快捷,所以使用 Spring2.x 或更高的版本能缩短开发周期,性能方面丝毫不逊色以前的 AOP 支持。