深入理解spring的AOP机制原理
前言 在软件开发中,散布于应用中多处的功能被称为横切关注点,通常来讲,这些横切关注点从概念上是与应用的业务逻辑相分离的。把这些横切关注点和业务逻辑分离出来正是AOP要解决的问题。AOP能够帮我们模块化横切关注点,换言之,横切关注点可以被描述为影响应用多出的功能。这些横切点被模块化特殊的类,这些类被称为切面。 术语定义 通知:切面有必须要完成的工作,在AOP中,切面的工作被称为通知。通知定义了切面是什么以及何时使用,除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题,它应该在某个方法之前?之后?之前和之后都调用?还是只在方法抛出异常时调用? 连接点:连接点是应用程序执行过程中,能够插入切面的一个点。 切点:是在连接点的基础上定义切点,比方说一个类由十几个方法,每个方法的调用前和调用后都可以插入通知,但是你只想选择几个方法插入通知,因此你定义一个切点来选择你想插入的通知的方法。 切面:切面就是通知和切点的结合。 织入:织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:编译期、类加载期、运行期。其中编译器织入需要特殊的编译器,类加载器织入需要特殊的类加载器,spring的AOP 是在运行期织入通知的。 Spring的AOP支持 spring提供了AOP的四种支持,分别是:基于代理的经典Spring AOP模式;纯POJO切面;@AspectJ注解驱动的切面;@注入式AspectJ切面。spring所创建的通知都是用标准的Java类编写的,而且定义通知所应用的切点通常会使用注解或在Spring配置文件里采用XML来编写。 spring只支持方法级别的连接点。 在spring AOP中,要使用AspectJ的切点表达式语言来定义切点,关于Spring AOP的AspectJ切点,最重要的一点就是Spring仅支持AspectJ切点指示器的一个子集: 1.arg() 限制连接点匹配参数为指定类型的执行方法; spring 注解创建切面 目标对象: package concert; public interface Performance{ public void perform(); } 切面对象: package concert; @Aspect//表示Audience的实例是一个切面 public class Audience{ @Before("execution(**concert.Performance.perform(..))") public void silenceCellPhones(){ //在perfrom方法执行之前 } @Before("execution(**concert.Performance.perform(..))") public void takeSeats(){ //在perfrom方法执行之前 } @AfterReturning("execution(**concert.Performance.perform(..))") public void silenceCellPhones(){ //在perfrom方法执行之后 } @AfterThrowing("execution(**concert.Performance.perform(..))") public void silenceCellPhones(){ //在perfrom方法抛出异常之后 } } 上面的类中切点表达式execution(**concert.Performance.perform(..))多次出现,我们也可以通过@Pointcut注解避免每次都写很长的切点表但是如下所示: @Aspect//表示Audience的实例是一个切面 public class Audience{ @Pointcut("execution(**concert.Performance.perform(..))") public void performance(){} @Before("performance()") public void silenceCellPhones(){ //在perfrom方法执行之前 } @Before("performance()") public void takeSeats(){ //在perfrom方法执行之前 } @AfterReturning("performance()") public void silenceCellPhones(){ //在perfrom方法执行之后 } @AfterThrowing("performance()") public void silenceCellPhones(){ //在perfrom方法抛出异常之后 } } 接下来需要在配置文件中配置切面如下所示: @Configuration @EnableAspectJAutoProxy//启动AspectJ自动代理 @ComponentScan public class ConcertConfig{ } //或者在配置文件中配置中添加 <aop:aspectj-autoproxy /> 表示启动切面代理 环绕通知: @Aspect//表示Audience的实例是一个切面 public class Audience{ @Pointcut("execution(**concert.Performance.perform(..))") public void performance(){} @Before("performance()") public void watchPerformance(ProceedingJoinPoint jp){ //在方法之前执行 System.out.println(" beform the method is invoked"); jp.proceed()//控制权交给目标方法 //在方法之后执行 System.out.println(" after the method is invoked"); } } 处理通知中的参数 public class Audience{ @Pointcut("execution(**concert.Performance.perform(int))&&args(trackNumber)") public void performance(){} @Before("performance(trackNumber)") public void watchPerformance(int trackNumber){ //截获传递给目标方法的参数并传递给切面中处理方法 System.out.println(trackNumber); } } xml中声明切面 spring AOP提供的xml配置元素: 1.<aop:advisor> 定义AOP通知; <aop:config> <aop:aspect ref="audience"> <aop:before pointcut="execution(**concert.Performance.perform())" method="silenceCellPhones"/> <aop:before pointcut="execution(**concert.Performance.perform())" method="takeSeats"/> <aop:after-returning pointcut="execution(**concert.Performance.perform())" method="applause"/> <aop:after-throwing pointcut="execution(**concert.Performance.perform())" method="demandRefund"/> </aop:aspect> </aop config> 定义切点: <aop:config> <aop:aspect ref="audience"> <aop:pointcut id="performance" expression="execution(**concert.Performance.perform())"> <aop:before pointcut-ref="performance" method="silenceCellPhones"/> <aop:before pointcut="performance" method="takeSeats"/> <aop:after-returning pointcut="performance" method="applause"/> <aop:after-throwing pointcut="performance" method="demandRefund"/> </aop:aspect> </aop config> 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |