Aspect-oriented Spring
cross-cutting concern:a cross-cutting concern can be described as any functionality that affects multiple points of an application:交叉问题的定义,如图所示
AOP术语:
- Advice:What & When ;可以理解为一个任务,什么时候要干的一个事情
- pointcuts:where;帮助缩小Join points的范围,确定到底在哪些地方加入aspect
- Join Point:
A join point is a point in the execution of the application where an aspect can be plugged in: 1. a method being called 2.an exception being thrown 3.a field being modified.
- ASPECTS:总和=Advice + pointcuts
- INTRODUCTIONS:在不改变类的前提下,给现有的类增加新的方法和属性。
- WEAVING:是将Aspects增加到现在对象中,创建新的代理对象的过程。这个过程可以在几个时间点发生:编译期;类记载时期;运行时;spring的 aop 是在运行时完成
AOP技术分类:
- AspectJ (http://eclipse.org/aspectj)
- JBoss AOP (http://www.jboss.org/jbossaop)
- Spring AOP (http://www.springframework.org) :只限于方法method的注入,如果需要字段和构造函数的注入,则需要运用AspectJ等框架的特殊语言
spring支持的pointcuts:spring的AOP是基于代理的AOP,其能力有限,支持下面的pointcuts:
- 其中,在所有上述的指示符中(designators),只有execution是真正去匹配的pointcus的,其它的指示符都是用于限制范围的。
- 所以在编程中,我们首要要关心的就是execution,如下例子:
- bean指示符:用于限定在某个特定ID的bean中
Spring aop 命名空间
- 旧式的基于ProxyFactoryBean的用法
- 新的基于XML的配置方法:
具体例子如下:
public class Audience { public void takeSeats() { System.out.println("The audience is taking their seats."); } public void turnOffCellPhones() { System.out.println("The audience is turning off their cellphones"); } public void applaud() { System.out.println("CLAP CLAP CLAP CLAP CLAP"); } public void demandRefund() { System.out.println("Boo! We want our money back!"); } } <bean id="audience" class="com.springinaction.springidol.Audience" /> <aop:config> <aop:aspect ref="audience"> <aop:before pointcut= "execution(* com.springinaction.springidol.Performer.perform(..))" method="takeSeats" /> <aop:before pointcut= "execution(* com.springinaction.springidol.Performer.perform(..))" method="turnOffCellPhones" /> <aop:after-returning pointcut= "execution(* com.springinaction.springidol.Performer.perform(..))" method="applaud" /> <aop:after-throwing pointcut= "execution(* com.springinaction.springidol.Performer.perform(..))" method="demandRefund" /> </aop:aspect> </aop:config>
- around方法:该方法中应该能做很多事情,例如权限检查,日志等:
public void watchPerformance(ProceedingJoinPoint joinpoint) { try { System.out.println("The audience is taking their seats."); System.out.println("The audience is turning off their cellphones"); long start = System.currentTimeMillis(); joinpoint.proceed(); long end = System.currentTimeMillis(); System.out.println("CLAP CLAP CLAP CLAP CLAP"); System.out.println("The performance took " + (end - start) + " milliseconds."); } catch (Throwable t) { System.out.println("Boo! We want our money back!"); } } <aop:config> <aop:aspect ref="audience"> <aop:pointcut id="performance2" expression= "execution(* com.springinaction.springidol.Performer.perform(..))" /> <aop:around pointcut-ref="performance2" method="watchPerformance()" /> </aop:aspect> </aop:config>
传递参数:Nevertheless, there are times when it may be useful for advice to not only wrap a method, but also inspect the values of the parameters passed to that method
- 探测被注入的方法的参数
增加新的方法:INTRODUCTIONS
-
<aop:aspect> <aop:declare-parents types-matching="com.springinaction.springidol.Performer+" implement-interface="com.springinaction.springidol.Contestant" default-impl="com.springinaction.springidol.GraciousContestant" /> </aop:aspect>
- As its name implies, <aop:declare-parents> declares that the beans it advises will have new parents in its object hierarchy.
基于注解的AOP
- <aop:aspectj-autoproxy /> :用于注册AnnotationAwareAspectJAutoProxyCreator
<aop:aspectj-autoproxy/> will create an AnnotationAwareAspectJAutoProxyCreator in the Spring context and will automatically proxy beans whose methods match the pointcuts defined with @Pointcut annotations in @Aspect-annotated beans.
@Aspect public class Audience { @Pointcut( "execution(* com.springinaction.springidol.Performer.perform(..))") public void performance() { } @Before("performance()") public void takeSeats() { System.out.println("The audience is taking their seats."); } @Before("performance()") public void turnOffCellPhones() { System.out.println("The audience is turning off their cellphones"); } @AfterReturning("performance()") public void applaud() { System.out.println("CLAP CLAP CLAP CLAP CLAP"); } @AfterThrowing("performance()") public void demandRefund() { System.out.println("Boo! We want our money back!"); } }