在Spring中,最常用的AOP框架是AspectJ,使用AspectJ实现AOP有2种方式:
基于XML的声明式AspectJ
1、在项目中添加包spring-aspects.jar(spring自带)、aspectjweaver.jar(需要自己下载添加)。
2、新建包user,包下新建类User
1 public class User{ 2 public void addUser(){ 3 System.out.println("正在添加用户"); 4 System.out.println("添加用户成功"); 5 } 6 }
User可实现接口。
3、新建包my_aspect,包下新建切面类MyAspect。注意是新建Class,不是新建Aspect。
1 public class MyAspect { 2 //前置通知 3 public void myBefore(){ 4 System.out.println("正在检查权限"); 5 System.out.println("权限已够"); 6 } 7 8 //后置通知 9 public void myAfterReturning(){ 10 System.out.println("正在记录日志"); 11 System.out.println("日志记录完毕"); 12 } 13 14 //环绕通知,同时在前后增强。 15 public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { 16 myBefore(); 17 Object object=proceedingJoinPoint.proceed(); 18 myAfterReturning(); 19 return object; 20 } 21 22 //异常通知 23 public void myAfterThrowing(Throwable e){ 24 System.out.println("出错了:"+e.getMessage()); 25 } 26 27 //最终通知 28 public void myAfter(){ 29 System.out.println("正在释放资源"); 30 System.out.println("资源释放完毕"); 31 } 32 }
根据需要,写通知。函数名是自定义的,但不能使用aspectj的关键字。
可使用形参 JoinPoint joinPoint ,通过 joinPoint.getSignature().getName() 获取增强的方法名。
4、在xml中配置
<!--目标类--> <bean id="user" class="user.User" /> <!--切面类--> <bean id="myAspect" class="my_aspect.MyAspect" /> <!--AOP配置--> <aop:config> <!--配置切面,一个aspect配置一个切面--> <aop:aspect ref="myAspect"> <!--配置全局切入点--> <aop:pointcut id="myPointCut" expression="execution(* user.*.*(..))" /> <!--配置要使用的通知--> <aop:before method="myBefore" pointcut-ref="myPointCut" /> <aop:after-returning method="myAfterReturning" pointcut="execution(void user.User.addUser())" /> </aop:aspect> </aop:config>
<aop:pointcut />配置的是全局切入点(所有通知都可引用),可在通知中使用pointcut-ref属性引用。也可以在单个通知中使用pointcut属性配置自己的切入点。
method属性指定这个通知对应的切面类中的方法。如果方法使用了参数JoinPoint(切入点),不用额外传参,pointcut/point-ref传递的就是切入点。
切入点指的就是目标方法。
- 前置通知
<aop:before method="myBefore" pointcut-ref="myPointCut" />
- 后置通知
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" />
后置通知可使用returning属性指定指定一个参数,这个参数表示目标方法的返回值,会被传递给后置通知的方法。returning属性只有后置通知能使用。
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="returnVal" />
- 环绕通知(前、后增强)
<aop:around method="myAround" pointcut-ref="myPointCut" />
环绕方法的参数 ProceedingJoinPoint proceedingJoinPoint 是JoinPoint的子类,不用额外传参。
如果同时使用前置/后置通知、环绕通知,则先执行环绕前,再执行前置(如果有),执行目标方法,执行后置(如果有),然后执行环绕后。
- 异常通知
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut&qu