在之前的读书笔记Spring in Acton 4读书笔记之AOP原理及Spring对AOP的支持中,讲到Spring对AOP的支持包含四方面:
- Spring基于代理的经典的AOP
- 使用XML配置将纯POJO转化为aspect
- 使用Spring的@Aspect标签,创建aspect
- Spring不创建aspect,只注入(引用)AspectJ框架的aspect
Spring in Action(Spring实战)的第四章第三节(4.3 Creating annotated aspects)讲述了其中第三种,即如何使用标签创建aspect。本文讲解其中的前面两小节:定义aspect以及创建around advice。
AspectJ 5引进的主要特性是使用标签创建aspect。AspectJ 5的缺点是需要学习扩展的java语言。但是AspectJ面向标签的编程模式使得将一个类转换成aspect变得很容易,只需要在类中加一些标签。
定义一个aspect
以下是使用标签创建AOP的例子,这个例子在之前的文章中有提到过,观众在演出开始前后,以及出问题时,会自动做出一些反应:
1 | package concert; |
Audience类上加上@Aspect,用来表示Audience是一个aspect,而Audience被标注的方法定义了具体的行为。在表演开始前,观众需要就座(takeSeats()),将手机静音(silenceCellPhones())。
表演结束后,观众需要鼓掌(applause()),如果表演过程中出现了异常,观众会要求退票(demandRefund())。AspectJ提供了五个标签来定义advice:
- @After,在方法正常执行结束,或者出现异常的时候,执行aspect。
- @AfterReturning,在方法正常执行结束后,执行aspect。
- @AfterThrowing,在方法抛出异常的时候,执行aspect。
- @Around,在方法执行过程中,执行aspect。
- @Before,在方法执行之前,执行aspect。
上面的例子中,所有标签的值都是一个pointcut表达式,而且在这个例子里,正好是一样的(因为是作用在同一个方法上)。实际上,可以将这个pointcut定义好,然后进行引用,这样可以避免重复编写pointcut。
1 |
|
上面的代码,使用@Pointcut标签对performance()方法进行标注,这样,就可以直接使用performance()来代替pointcut表达式了。performance()只是一个标记,所以方法体可以也必须是空的。
如果只是定义了上面Audience这个aspect,那么其实什么也做不了。必须有一个配置文件,指出它是一个aspect,并且解析这些标签,然后创建代理,最终将Audience转化为一个aspect。
如果是使用JavaConfig,可以在配置文件类加上@EnableAspectJAutoProxy标签,以实现自动代理。以下是示例:
1 |
|
Spring使用AspectJ进行自动代理,仅仅是使用@AspectJ的标签作为指引,而底层仍然是Spring自己的基于代理的aspect。所以,尽管使用了@AspectJ标签,Spring的AOP仍然只能作用在方法级别。如果要使用AspectJ的全部功能,就必须在运行时注入AspectJ,而不使用Spring来创建基于代理的aspect。
创建一个around advice
前面讲解了before和after的用法,由于around的用法有些不同,也更有用,所以这里单讲。先看看下面的例子:
1 |
|
使用@Around标签标注了watchPerformance方法,监听performance()代表的joinpoint。此时,watchPerformance的参数ProceedingJoinPoint就是指这个joinpoint。可以看到,在jp.proceed()的前后各有一些操作,甚至在抛出异常时,也有一些处理。所以,这个方法同时实现@Before、@AfterReturning和@AfterThrowing等标签的功能,更加灵活。
需要注意的是,必须执行joinpoint的proceed()方法,否则,会导致被监听的方法没有执行。
我计划完成50到100篇关于Spring的文章,这是第十一篇,欢迎订阅tantanit.com,第一时间获取文章更新,本文链接地址:http://tantanit.com/springinaction4-du-shu-bi-ji-zhi-shi-yong-biao-qian-chuang-jian-aop/