在Spring 2.0中,除了传统的通过实现AOP AIP的方式来实现Advice之外,还提供了两种更加简便的方式来实现Advice:1)基于XML Schema的设置;2)基于Annotation的支持,采用这两种方式,Advice将不用实现特定的接口。现在让我们来看看如何使用这两种方式来分别实现Before Advice、After Advice、Around Advice、Throwing Advice
。
一、Before Advice:基于 XML Schema
当基于XML Schema实现Before Advice时,你的Advice类不用实现org.springframework.aop.MethodBeforeAdvice接口,例如:
java代码
before 方法是在目标对象上的方法被执行前要执行的方法,before方法中的JoinPoint参数是可选项,你可以根据需要决定是否需要JoinPoint参数,通过JoinPoint对象,你可以获得目标对象(getTarget())、目标方法上的参数(getArgs())等信息。
然后在XML中为目标对象指定LogBeforeAdvice 代理:
一、Before Advice:基于 XML Schema
当基于XML Schema实现Before Advice时,你的Advice类不用实现org.springframework.aop.MethodBeforeAdvice接口,例如:
java代码
package com.savage.aop;
import org.aspectj.lang.JoinPoint;
public class LogBeforeAdvice {
public void before(JoinPoint joinPoint) {
System.out.println("Logging before " + joinPoint.getSignature().getName());
}
}
before 方法是在目标对象上的方法被执行前要执行的方法,before方法中的JoinPoint参数是可选项,你可以根据需要决定是否需要JoinPoint参数,通过JoinPoint对象,你可以获得目标对象(getTarget())、目标方法上的参数(getArgs())等信息。
然后在XML中为目标对象指定LogBeforeAdvice 代理:
xml 代码
如上所示,在 Spring 2.0 中要使用基于 XML Sechma 声明 AOP 的方式,需要在 XML 中加入 aop 的名称空间。当基于 XML Sechma 实现 AOP 时,所有的 AOP 都是在 <aop:config></aop:config> 标签中声明的, <aop:aspect></aop:aspect> 用于定义 Advice 实例。 <aop:before></aop:before> 表示当前实例用于实现 Before Advice ; pointcut 属性用于指定 pointcut 表示式,上面的例子表示此 Advice 将应用于 com.savage.aop.MessageSender 接口中的任何方法; method 属性表示 Advice 上要调用的方法。
现在调用任何 MessageSender 接口上的方法之前都会执行 LogBeforeAdvice 的 before 方法,例如:
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="messageSender" class="com.savage.aop.HttpMessageSender"></bean>
<bean id="logBeforeAdvice" class="com.savage.aop.LogBeforeAdvice"></bean>
<aop:config>
<aop:aspect id="logBefore" ref="logBeforeAdvice">
<aop:before pointcut="execution(* com.savage.aop.MessageSender.*(..))"
method="before"/>
</aop:aspect>
</aop:config>
</beans>
如上所示,在 Spring 2.0 中要使用基于 XML Sechma 声明 AOP 的方式,需要在 XML 中加入 aop 的名称空间。当基于 XML Sechma 实现 AOP 时,所有的 AOP 都是在 <aop:config></aop:config> 标签中声明的, <aop:aspect></aop:aspect> 用于定义 Advice 实例。 <aop:before></aop:before> 表示当前实例用于实现 Before Advice ; pointcut 属性用于指定 pointcut 表示式,上面的例子表示此 Advice 将应用于 com.savage.aop.MessageSender 接口中的任何方法; method 属性表示 Advice 上要调用的方法。
现在调用任何 MessageSender 接口上的方法之前都会执行 LogBeforeAdvice 的 before 方法,例如:
java 代码
二、 Before Advice :基于 Annotation
使用 Annotation 来实现 Advice ,在 XML 文件上的定义要比基于 XML Sechema 的方法要简便的多,但在实现 Before Advice 类时,则需要使用到 @Aspect 、 @Before 标识,并需要引入 org.aspectj.lang.annotation 包中的类。还以 LogBeforeAdvice 为例, LogBeforeAdvice 类需要改为:
如上所示,通过 @Aspect 将一个类声明为 Aspect 类,通过 @Before 将方法声明 Before Advice ,方法中的 JoinPoint 同样是可选的。 然后在 XML 文件中做如下定义:
package com.savage.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AdviceDemo {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("beans-config.xml");
MessageSender sender = (MessageSender)context.getBean("messageSender");
sender.sendMessage("message");
}
}
二、 Before Advice :基于 Annotation
使用 Annotation 来实现 Advice ,在 XML 文件上的定义要比基于 XML Sechema 的方法要简便的多,但在实现 Before Advice 类时,则需要使用到 @Aspect 、 @Before 标识,并需要引入 org.aspectj.lang.annotation 包中的类。还以 LogBeforeAdvice 为例, LogBeforeAdvice 类需要改为:
java 代码
通过aop命名空间的 <aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean
创建代理,织入切面。当然,spring在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了, <aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
package com.savage.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class LogBeforeAdvice {
@Before("execution(* com.savage.aop.MessageSender.*(..))")
public void before(JoinPoint joinPoint) {
System.out.println("Logging before " + joinPoint.getSignature().getName());
}
}
通过aop命名空间的 <aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean
如上所示,通过 @Aspect 将一个类声明为 Aspect 类,通过 @Before 将方法声明 Before Advice ,方法中的 JoinPoint 同样是可选的。 然后在 XML 文件中做如下定义:
xml 代码
所有基于 Annotation 实现的 Advice ,在 XML 文件中都只要使用 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 进行设置就可以了,非常简单。
三、 After Advice :基于 XML Sechma
和 Before Advice 一样,基于 XML Sechma 实现 After Returning Advice 时,不再需要 org.springframework.aop.AfterReturningAdvice 接口:
八、 Throw Advice :基于 Annotation
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="messageSender" class="com.savage.aop.HttpMessageSender"></bean>
<bean id="logBeforeAdvice" class="com.savage.aop.LogBeforeAdvice"></bean>
<aop:aspectj-autoproxy/>
</beans>
所有基于 Annotation 实现的 Advice ,在 XML 文件中都只要使用 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 进行设置就可以了,非常简单。
三、 After Advice :基于 XML Sechma
和 Before Advice 一样,基于 XML Sechma 实现 After Returning Advice 时,不再需要 org.springframework.aop.AfterReturningAdvice 接口:
java 代码
然后在 XML 中做如下设置:
四、 After Advice :基于 Annotation
和 Before Advice 相似,使用 @AfterReturning 来表示 After Returning Advice :
这里和 Before Advice 有点不同的是,在定义 Poincut 表示式时,多了一个 returning 属性,用于指定目标方法执行完后的返回值。
XML 文件中的设置与 LogBeforeAdvice 的相似(将 logBeforeAdvice 的定义改为 logAfterReturning 的定义),不再列举。
五、 Around Advice :基于 XML Sechma
在 Spring 2.0 中, Around Advice 不用实现 org.aoplliance.intercept.MethodInterceptor 接口,但 Advice 的方法必须返回对象,并且必须定义一个 ProceedingJoinPoint 参数,例如:
XML 中的设置如下:
六、 Around Advice :基于 Annotation
和 Before Advice 相似,使用 @Around 来表示 Around Advice :
七、 Throw Advice :基于 XML Sechma
在 Spring 2.0 中, Throw Advice 不用实现 org.springframework.aop.ThrowsAdvice 接口,但 Advice 的方法必须定义 Throwable (或其子类)参数,例如:
在
<aop:after-throwing></aop:after-throwing>
中必须定义
throwing
属性,指定方法中的
throwable
参数。
Spring
将根据异常类型决定是否调用
afterThrowing
方法。package com.savage.aop;
import org.aspectj.lang.JoinPoint;
public class LogAfterReturningAdvice {
public void afterReturning(JoinPoint joinPoint) {
System.out.println("Logging after " + joinPoint.getSignature().getName());
}
}
然后在 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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="messageSender" class="com.savage.aop.HttpMessageSender"></bean>
<bean id="logAfterReturningAdvice"
class="com.savage.aop.LogAfterReturningAdvice"></bean>
<aop:config>
<aop:aspect id="logAfterReturning" ref="logAfterReturningAdvice">
<aop:after-returning
pointcut="execution(* com.savage.aop.MessageSender.*(..))"
method="afterReturning"/>
</aop:aspect>
</aop:config>
</beans>
四、 After Advice :基于 Annotation
和 Before Advice 相似,使用 @AfterReturning 来表示 After Returning Advice :
java 代码
package com.savage.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningAdvice {
@AfterReturning(pointcut="execution(* com.savage.aop.MessageSender.*(..))",
returning="retVal")
public void afterReturning(JoinPoint joinPoint, Object retVal) {
System.out.println("Logging after " + joinPoint.getSignature().getName());
}
}
这里和 Before Advice 有点不同的是,在定义 Poincut 表示式时,多了一个 returning 属性,用于指定目标方法执行完后的返回值。
XML 文件中的设置与 LogBeforeAdvice 的相似(将 logBeforeAdvice 的定义改为 logAfterReturning 的定义),不再列举。
五、 Around Advice :基于 XML Sechma
在 Spring 2.0 中, Around Advice 不用实现 org.aoplliance.intercept.MethodInterceptor 接口,但 Advice 的方法必须返回对象,并且必须定义一个 ProceedingJoinPoint 参数,例如:
java 代码
package com.savage.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class LogAroundAdvice {
public Object invoke(ProceedingJoinPoint joinPoint) {
System.out.println("Logging before " + joinPoint.getSignature().getName());
Object retVal = joinPoint.proceed();
System.out.println("Logging after " + joinPoint.getSignature().getName());
return retVal;
}
}
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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="messageSender" class="com.savage.aop.HttpMessageSender"></bean>
<bean id="logAroundAdvice" class="com.savage.aop.LogAroundAdvice"></bean>
<aop:config>
<aop:aspect id="logAround" ref="logAroundAdvice">
<aop:around
pointcut="execution(* com.savage.aop.MessageSender.*(..))"
method="invoke"/>
</aop:aspect>
</aop:config>
</beans>
六、 Around Advice :基于 Annotation
和 Before Advice 相似,使用 @Around 来表示 Around Advice :
java 代码
package com.liuyoung.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class LogAroundAdvice {
@Around("execution(* com.savage.aop.MessageSender.*(..))")
public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Logging before [log around advice] : " + joinPoint.getSignature().getName());
Object retVal = joinPoint.proceed();
System.out.println("Logging after [log around advice] : " + joinPoint.getSignature().getName());
return retVal;
}
}
七、 Throw Advice :基于 XML Sechma
在 Spring 2.0 中, Throw Advice 不用实现 org.springframework.aop.ThrowsAdvice 接口,但 Advice 的方法必须定义 Throwable (或其子类)参数,例如:
java 代码
在 XML 的设置如下:
package com.savage.aop;
import org.aspectj.lang.JoinPoint;
public class LogThrowingAdvice {
public void afterThrowing (JoinPoint joinPoint, Throwable throwable) {
System.out.println("Logging when throwing " + joinPoint.getSignature().getName());
}
}
在 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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="messageSender" class="com.savage.aop.HttpMessageSender"></bean>
<bean id="logThrowingAdvice" class="com.savage.aop.LogThrowingAdvice"></bean>
<aop:config>
<aop:aspect id="logThrowing" ref="logThrowingAdvice">
<aop:after-throwing
pointcut="execution(* com.savage.aop.MessageSender.*(..))"
throwing="throwable"
method="afterThrowing"/>
</aop:aspect>
</aop:config>
</beans>
八、 Throw Advice :基于 Annotation
java 代码
package com.savage.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingAdvice {
@AfterThrowing(pointcut="execution(* com.savage.aop.MessageSender.*(..))",
throwing="throwable")
public void afterThrowing(JoinPoint joinPoint, Throwable throwable) {
System.out.println("Logging when throwing "
+ joinPoint.getSignature().getName());
}
}