注解方式的确更加简洁,由配置优先转为契约优先,还是需要点过程,至少是理解上和心理上!
![21232604_w77L.gif](http://static.oschina.net/uploads/img/201212/21232604_w77L.gif)
先看Spring配置文件:
- <?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.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
- >
- <!-- proxy-target-class默认"false",更改为"ture"使用CGLib动态代理 -->
- <aop:aspectj-autoproxy proxy-target-class="true" />
- <bean
- id="hello"
- class="org.zlex.aop.SayHello" />
- <bean class="org.zlex.aop.AspectJAdvice" />
- </beans>
<aop:aspectj-autoproxy /> 打开自动代理, proxy-target-class 默认"false"使用JDK代理,更改为"ture"使用CGLib动态代理。
org.zlex.aop.AspectJAdvice 是在上一篇Advice类的AspectJ注解实现。
逐步解析。。。
@Aspect 标注AspectJ的实现类:
- @Aspect
- public class AspectJAdvice {
- // ...
- }
先来看BeforeAdvice,实现方法如下:
- /**
- * @param joinPoint
- */
- @Before("execution(* org.zlex.aop.Hello.sayHelloBefore(..))")
- public void beforeAdvice(JoinPoint joinPoint) {
- System.out.println("Before: " + joinPoint.getSignature().getName());
- }
@Before("execution(* org.zlex.aop.Hello.sayHelloBefore(..))") 也可以写成 @Before(value="execution(* org.zlex.aop.Hello.sayHelloBefore(..))") 。
当执行 org.zlex.aop.Hello.sayHelloBefore(..) 方法时,将触发beforeAdvice方法。
AfterAdvice和AroundAdvice与之类似,代码如下:
- /**
- * After
- *
- * @param joinPoint
- */
- @After (value = "execution(* org.zlex.aop.Hello.sayHelloAfter(..))")
- public void afterAdvice(JoinPoint joinPoint) {
- System.out.println("After: " + joinPoint.getSignature().getName());
- }
- /**
- * Around
- *
- * @param joinPoint
- * @return
- * @throws Throwable
- */
- @Around(value = "execution(* org.zlex.aop.Hello.sayHelloAround(..))")
- public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
- System.out.println("Around: " + joinPoint.getSignature().getName());
- System.out.println("Before");
- Object obj = joinPoint.proceed();
- System.out.println("End");
- return obj;
- }
只是这里的AroundAdvice在实现方法时,需要 ProceedingJoinPoint 作为参数,用于执行环绕方法,并将执行结果返回。
AfterReturningAdvice可以获取目标方法的返回值,代码如下:
- /**
- * AfterReturning
- *
- * @param joinPoint
- */
- @AfterReturning(value = "execution(* org.zlex.aop.Hello.sayHelloAfterReturning(..))", returning = "retVal")
- public void afterReturningAdvice(JoinPoint joinPoint, String retVal) {
- System.out.println("AfterReturning: "
- + joinPoint.getSignature().getName());
- System.out.println("Return Value: " + retVal);
- }
@AfterReturning(value = "execution(* org.zlex.aop.Hello.sayHelloAfterReturning(..))", returning = "retVal") 中,有一个注解参数 returning 用于标识返回值参数,与方法中的参数名称保持一致即可。
AfterThrowingAdvice与AfterReturningAdvice类似,可以获得目标对象抛出的异常,代码如下:
- /**
- * AfterThrowing
- *
- * @param joinPoint
- */
- @AfterThrowing(value = "execution(* org.zlex.aop.Hello.sayHelloAfterThrowing(..))", throwing = "e")
- public void afterThrowingAdvice(JoinPoint joinPoint, Exception e) {
- System.out.println("AfterThrowing: "
- + joinPoint.getSignature().getName());
- System.out.println("Exception Message: " + e.getMessage());
- }
这里需要着重说明的是Introduction的注解实现方式,代码如下:
- @DeclareParents(value = "org.zlex.aop.SayHello", defaultImpl = org.zlex.aop.IntroductionOk.class)
- public Ok ok;
这里的Ok接口,用来扩展原有SayHello。 这个成员变量(ok)必须标示为public,即public Ok ok; 。
@DeclareParents 参数中, defaultImpl 指向 Ok 接口的实现类, value 标识目标类。比起Schema的繁杂配置,可谓是一步到位!