在
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 接口,例如:
before方法是在目标对象上的方法被执行前要执行的方法, before方法中的 JoinPoint参数是可选项,你可以根据需要决定是否需要 JoinPoint参数,通过 JoinPoint对象,你可以获得目标对象( getTarget())、目标方法上的参数( getArgs())等信息。
然后在 XML中为目标对象指定 LogBeforeAdvice代理:
如上所示,在 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方法,例如:
二、 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文件中做如下定义:
所有基于 Annotation实现的 Advice,在 XML文件中都只要使用 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>进行设置就可以了,非常简单。
三、 After Advice:基于 XML Sechma
和 Before Advice一样,基于 XML Sechma实现 After Returning Advice时,不再需要 org.springframework.aop.AfterReturningAdvice接口:
然后在 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:
XML文件中的设置与 LogBeforeAdvice的相似(将 logBeforeAdvice的定义改为 logAroundAdvice的定义),不再列举。
七、 Throw Advice:基于 XML Sechma
在 Spring 2.0中, Throw Advice不用实现 org.springframework.aop.ThrowsAdvice接口,但 Advice的方法必须定义 Throwable(或其子类)参数,例如:
在 XML的设置如下:
在 <aop:after-throwing></aop:after-throwing>中必须定义 throwing属性,指定方法中的 throwable参数。 Spring将根据异常类型决定是否调用 afterThrowing方法。
八、 Throw Advice:基于 Annotation
XML文件中的设置与 LogBeforeAdvice的相似(将 logBeforeAdvice的定义改为 logThrowingAdvice的定义),不再列举。
一、 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 代码
- <?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 代码
- 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 代码
- 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());
- }
- }
如上所示,通过 @Aspect将一个类声明为 Aspect类,通过 @Before将方法声明 Before Advice,方法中的 JoinPoint同样是可选的。然后在 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="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 代码
- 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="logAfterReturning"/>
- </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 void 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.savage.aop;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Around;
- @Aspect
- public class AfterReturningAdvice {
- @Around("execution(* com.savage.aop.MessageSender.*(..))")
- public void 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文件中的设置与 LogBeforeAdvice的相似(将 logBeforeAdvice的定义改为 logAroundAdvice的定义),不再列举。
七、 Throw Advice:基于 XML Sechma
在 Spring 2.0中, Throw Advice不用实现 org.springframework.aop.ThrowsAdvice接口,但 Advice的方法必须定义 Throwable(或其子类)参数,例如:
java 代码
- 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>
在 <aop:after-throwing></aop:after-throwing>中必须定义 throwing属性,指定方法中的 throwable参数。 Spring将根据异常类型决定是否调用 afterThrowing方法。
八、 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());
- }
- }
XML文件中的设置与 LogBeforeAdvice的相似(将 logBeforeAdvice的定义改为 logThrowingAdvice的定义),不再列举。