引贴:java
Aspectj与Spring AOP比较
AspectJ语法详解
Spring中的AOP(五)——在Advice方法中获取目标方法的参数spring
//定义切面 public class SleepHelperAspect{ public void beforeSleep(){ System.out.println("睡觉前要脱衣服!"); } public void afterSleep(){ System.out.println("起床后要穿衣服!"); } }
<bean id="sleepHelperAspect" class="com.ghs.aop.SleepHelperAspect"></bean> <aop:aspectj-autoproxy/> <aop:config> <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/> <aop:aspect ref="sleepHelperAspect"> <!--前置通知--> <aop:before method="beforeSleep" pointcut-ref="sleepPointcut"/> <!--后置通知--> <aop:after method="afterSleep" pointcut-ref="sleepPointcut"/> </aop:aspect> </aop:config>
//定义通知 public class SleepHelper implements MethodBeforeAdvice,AfterReturningAdvice{ @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("睡觉前要脱衣服!"); } @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { System.out.println("起床后要穿衣服!"); } }
<bean id="sleepHelper" class="com.noob.aop.SleepHelper"></bean> <aop:aspectj-autoproxy/> <aop:config> <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/> <aop:advisor advice-ref="sleepHelper" pointcut-ref="sleepPointcut"/> </aop:config>
表示式(expression)和签名(signature)express
//Pointcut表示式 @Pointcut("execution(* com.savage.aop.MessageSender.*(..))") //Point签名 private void log(){}
由下列方式来定义或者经过 &&、 ||、 !、 的方式进行组合:框架
execution:用于匹配方法执行的链接点;ide
within:用于匹配指定类型内的方法执行;this
this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配; spa
target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;.net
args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;3d
@within:用于匹配因此持有指定注解类型内的方法;代理
@target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
@args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
@annotation:用于匹配当前执行方法持有指定注解的方法;
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
其中后面跟着“?”的是可选项
括号中各个pattern分别表示:
eg.
- 任意公共方法的执行:execution(public * *(..))
- 任何一个以“set”开始的方法的执行:execution(* set*(..))
- AccountService 接口的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))
- 定义在service包里的任意方法的执行: execution(* com.xyz.service.*.*(..))
- 定义在service包和全部子包里的任意类的任意方法的执行:execution(* com.xyz.service..*.*(..))
第一个*表示匹配任意的方法返回值, ..(两个点)表示零个或多个,第一个..表示service包及其子包,第二个*表示全部类, 第三个*表示全部方法,第二个..表示方法的任意参数个数- 定义在pointcutexp包和全部子包里的JoinPointObjP2类的任意方法的执行:execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
- pointcutexp包里的任意类: within(com.test.spring.aop.pointcutexp.*)
- pointcutexp包和全部子包里的任意类:within(com.test.spring.aop.pointcutexp..*)
- 实现了Intf接口的全部类,若是Intf不是接口,限定Intf单个类:this(com.test.spring.aop.pointcutexp.Intf)
当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型- 带有@Transactional标注的全部类的任意方法:
- @within(org.springframework.transaction.annotation.Transactional)
- @target(org.springframework.transaction.annotation.Transactional)
- 带有@Transactional标注的任意方法:@annotation(org.springframework.transaction.annotation.Transactional)
@within和@target针对类的注解,@annotation是针对方法的注解- 参数带有@Transactional标注的方法:@args(org.springframework.transaction.annotation.Transactional)
- 参数为String类型(运行是决定)的方法: args(String)
当使用@Around处理时,须要将第一个参数定义为ProceedingJoinPoint类型,该类是JoinPoint的子类。
经常使用的方法:
@AfterReturning( pointcut="execution(* com.abc.service.*.access*(..)) && args(time, name)", returning="returnValue") public void access(Date time, Object returnValue, String name) { System.out.println("目标方法中的参数String = " + name); System.out.println("目标方法中的参数Date = " + time); System.out.println("目标方法的返回结果returnValue = " + returnValue); }
表达式中增长了args(time, name)部分,意味着能够在加强处理的签名方法(access方法)中定义"time"和"name"两个同名属性。
这两个形参的类型由access方法同名参数类型指定,一旦指定了, 则这两个形参类型将用于限制该切入点只匹配第一个参数类型为Date,第二个参数类型为String的方法(方法参数个数和类型如有不一样均不匹配);
access方法只须要知足"time", "name"参数的顺序和pointcut中args(time, name)的顺序相同便可,"returnValue"位置顺序无所谓。
eg.
//将被access方法匹配 public String accessAdvice(Date d, String n) { System.out.println("方法:accessAdvice"); return "aa"; }
正常:
异常:
优先级高的切面类里的加强处理的优先级老是比优先级低的切面类中的加强处理的优先级高。
在“进入”链接点时,最高优先级的加强处理将先被织入(eg.给定的两个不一样切面类Before加强处理中,优先级高的那个会先执行);在“退出”链接点时,最高优先级的加强处理会最后被织入(eg.给定的两个不一样切面类After加强处理中,优先级高的那个会后执行)。
eg.
优先级为1的切面类Bean1包含了@Before,优先级为2的切面类Bean2包含了@Around,虽然@Around优先级高于@Before,但因为Bean1的优先级高于Bean2的优先级,所以Bean1中的@Before先被织入。
Spring提供了以下两种解决方案指定不一样切面类里的加强处理的优先级:
同一个切面类里的两个相同类型的加强处理在同一个链接点被织入时,Spring AOP将以随机的顺序来织入这两个加强处理,没有办法指定它们的织入顺序。即便给这两个 advice 添加了 @Order 这个注解,也不行!