1.什么是AOP
AOP(面向切面编程)给我们提供了很好的非入侵式(在不修改源代码的情况下)的手段为现有的类增加新的功能。本文通过演示 Spring AOP 是如何使用的来介绍什么是 AOP。
我们会首先演示如何使用基于注解的 Spring AOP,然后演示如何使用基于 XML 的 Spring AOP。最后对 Spring AOP 进行简要的总结。
首先我们需要定义一个目标对象(接口),这个对象在调用某些方法时(之前或之后)会被拦截,然后执行我们自己的代码。
1 2 3 4
| package concert; public interface Performance { public void perform(); }
|
假定上面的对象就是我们的目标类。我们希望在该类调用 perform() 方法之前和之后分别输出一些提示,但是处于某些原因,我们又不想修改它的源代码。为了实现这一目标,我们需要使用 AOP 来达到我们的目的。
2.基于注解的 Spring AOP
下面是一个 Audience 类,它在本文中作为一个切面来使用。也就是说,在 Performance 类调用 perform() 前后输出的提示,其实是由 Audience 提供的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package concert; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public calss Audience { @Pointcut("execution(** concert.Performance.perform(..))") public void performance() {} @Before("performance()") public void silencePhones() { System.out.println("Siliencing phones."); } @AfterReturning("performance()") public void clap() { System.out.println("Claping."); } @AfterThrowing(“Performance()”) public void refund() { System.out.println("Demanding a refund"); } }
|
为了使 Spring 能够识别 @Aspect 注解,我们需要在 JavaConfig 中启用 AspectJ 注解的自动代理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package concert; import org.aspectj.lang.annotation.Bean; import org.aspectj.lang.annotation.ComponentScan; import org.aspectj.lang.annotation.Configuration; import org.aspectj.lang.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy @ComponentScan public class ConcertConfig { @Bean public Audience audience() { return new Audience(); } }
|
3.基于 XML 的 Spring AOP
使用注解的 AOP 能够在不侵入目标类的情况下,对目标类的方法进行监控。但是,如果切面 Audience 的代码中有许多注解。试想,如果我们连切面的代码都不想修改,或者无法修改切面的源代码,我们又该如何使用 AOP 呢?XML 为我们提供了一种解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package concert; public calss Audience { public void silencePhones() { System.out.println("Siliencing phones."); } public void clap() { System.out.println("Claping."); } public void refund() { System.out.println("Demanding a refund"); } }
|
我们去掉了 Audience 中所有的注解,当然这样的一个类是无法实现 AOP 的,因此我们需要在XML 中进行配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <aop:config> <aop:aspect ref="audience"> <aop:pointcut id="performance" expression="execution(** concert.Performance.perform(..))" /> <aop:before pointcut-ref="performance" method="soliencePhones"/> <aop:after-returning pointcut-ref="performance" method="clap"/> <aop:after-throwing pointcut-ref="performance" method="refund"/> </aop:aspect> </aop:config>
|
这样一来,我们就可以在两个类都是完全的 pojo 类(纯 java 代码实现的普通类)的情况下实现 aop 了。