Spring AOP 的注解实现

2016-03-28 20:48:43   最后更新: 2017-03-09 17:46:10   访问数量:636




上一篇日志中,我们讲解了如何创建并使用切面,AspectJ5 引入了使用注解来创建切面的新特性

使用注解的方式定义切面,为应用程序带来了非常大的便捷性,也让代码更加美观

在学习了上一篇日志中使用 xml 定义切面以后,这一节中的介绍会让你觉得非常简单

Spring 面向切面实例讲解

 

为了支持使用注解定义面向切面的功能,需要在 xml 中写入:

<aop:aspectj-autoproxy/> <!-- 支持面向切面注解 -->

 

 

还记得上一篇日志中的 Audience 类吗?现在我们只需要为他的每个方法都加上一个注解,而舍弃冗长的 xml:

package com.techlog.test.service; import org.aspectj.lang.annotation.*; /** * Created by techlog on 16/3/25. */ @Aspect public class Audience { @Pointcut("execution(* com.techlog.test.service.Performer.perform(..))") // 定义切点 public void performance() { } @Before("performance()") public void takeSteats() { System.out.println("taking seats"); } @Before("performance()") public void turnOffCellPhones() { System.out.println("turning off phones"); } @AfterReturning("performance()") public void applaud() { System.out.println("clap clap"); } @AfterThrowing("performance()") public void demandRefund() { System.out.println("refunding money"); } }

 

 

你会发现注解和之前的 xml 配置简直是一一对应,异曲同工的,这里就不多做说明了

 

接下来,只需要在 xml 配置文件中创建 Audience 的 bean,让 Spring 加载他就可以了:

<bean id="audience" class="com.techlog.test.service.Audience"/>

 

 

注解环绕通知与前置后置通知类似:

package com.techlog.test.service; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; /** * Created by techlog on 16/3/25. */ @Aspect public class Audience { @Pointcut("execution(* com.techlog.test.service.Performer.perform(..))") public void performance() { } // 定义切点 @Around("performance()") public void watchPerformance(ProceedingJoinPoint joinPoint) { System.out.println("taking seats"); System.out.println("turning off phones"); long start = System.currentTimeMillis(); try { joinPoint.proceed(); } catch (Throwable throwable) { System.out.println("refunding money"); return; } System.out.println("clap clap"); System.out.println("The performance took " + (System.currentTimeMillis() - start) + " milliseconds"); } }

 

 

与上一篇日志中的 XML 非常类似,使用注解也可以实现向通知传递参数:

package com.techlog.test.service.implement; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; /** * Created by techlog on 16/3/28. */ @Aspect public class Magician { private String thoughts; @Pointcut("execution(* com.techlog.test.service.Thinker.think(String)) && args(thoughts)") // 定义切点 public void thinking(String thoughts) {} @Before(value = "thinking(thoughts)", argNames = "thoughts") public void interceptThoughts(String thoughts) { System.out.println(thoughts); this.thoughts = thoughts; } public String getThoughts() { return thoughts; } }

 

 

为了实现上一篇日志中讲到的向某个类引入接口的功能,我们可以使用 <aop:declare-parents> 标签,与他等效的,我们可以使用 @DeclareParents 注解实现

package com.techlog.test.service; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; @Aspect public class ContestantIntroducer { @DeclareParents( value = "com.techlog.test.service.Performer+" defaultImpl = GraciousContestant.class) public static Contestant contestant; }

 

 

ContestantIntroducer 就是我们创建的切面,他为 Performer 类引入了 Contestant 接口

 

如果我们的项目中有多个切面,那么就有可能出现一个方法被多个切面切到的情况,这时我们就需要控制是哪个切面先开始执行,这就体现出了为切面设置优先级的重要性

事实上,为切面设置优先级的方法是非常简单的,Spring 提供了 Order 注解来实现对切面优先级的设置:

@Aspect @Service @Order(1) public class MyAspect { }

 

 

如上面的例子,在创建切面时,通过 @Order 注解传入优先级即可指定该切面的优先级,数字越小优先级越高,可以为负数

同时,spring 还提供了 Ordered 接口,封装有两个静态域:

public interface Ordered { /** * Useful constant for the highest precedence value. * @see java.lang.Integer#MIN_VALUE */ int HIGHEST_PRECEDENCE = Integer.MIN_VALUE; /** * Useful constant for the lowest precedence value. * @see java.lang.Integer#MAX_VALUE */ int LOWEST_PRECEDENCE = Integer.MAX_VALUE; /** * Return the order value of this object, with a * higher value meaning greater in terms of sorting. * <p>Normally starting with 0, with <code>Integer.MAX_VALUE</code> * indicating the greatest value. Same order values will result * in arbitrary positions for the affected objects. * <p>Higher values can be interpreted as lower priority. As a * consequence, the object with the lowest value has highest priority * (somewhat analogous to Servlet "load-on-startup" values). * @return the order value */ int getOrder(); }

 

Ordered.HIGHEST_PRECEDENCE 和 Ordered.LOWEST_PRECEDENCE 分别定义了最高优先级与最低优先级

 






技术帖      web      龙潭书斋      framework      spring      ioc      aop      注解      设计模式      aspect      aspectj     


京ICP备15018585号