在前两篇博客中,介绍了AOP实现的基础:静态代理和动态代理,这篇博客介绍spring中AOP的实现。
一、采用Annotation方式
首先引入jar包:aspectjrt.jar && aspectweaver.jar
applicationContext配置文件:
<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> <!-- 启用AspectJ对Annotation的支持 --> <span style="color:#ff0000;"><aop:aspectj-autoproxy/></span> <bean id="user" class="com.angel.spring.User"/> <bean id="successfulHandler" class="com.angel.spring.SuccessfulHandler"/> </beans> </span>接口和实现类省略
代理拦截类:
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.spring; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class SuccessfulHandler { /** * 定义Pointcut,Pointcut的名称为addAddMethod(),此方法没有返回值和参数 * 该方法就是一个标识,不进行调用 */ @Pointcut("execution(* add*(..))") private void addAddMethod(){}; /** * 定义Advice,表示我们的Advice应用到哪些Pointcut订阅的Joinpoint上 */ //@Before("addAddMethod()") @After("addAddMethod()") private void checkSecurity() { System.out.println("-------Angel,方法执行成功!-------"); } } </span>通过以上的配置,就可以实现对于方法调用的拦截。我们使用的注解有@Aspect,标记此类是一个横切面的插入类(拦截类),然后使用@Pointcut,标记我们的拦截方法需要作用于那些地方,最后使用@Before或者@After标记我们的拦截方法是作用于被调用方法前或者后。
但是,通过注解的方式,我们就需要为每个方法都添加注解,如果要修改的话,还得逐一修改,这样子,虽然同样轻便,但是如果有一个地方统一配置AOP的话,那就会更为简便,接下来,我们看第二种实现方式:采用配置方式
二、采用配置方式
applicationContext的配置:<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> <!-- 启用AspectJ对Annotation的支持 --> <!-- <aop:aspectj-autoproxy/> --> <bean id="user" class="com.angel.spring.User" /> <bean id="successfulHandler" class="com.angel.spring.SuccessfulHandler" /> <aop:config> <aop:aspect id="IsSuccessfulAspect" ref="successfulHandler"> <!-- com.bjpowernode.spring包下所有的类所有的方法 <aop:pointcut id="addAddMethod" expression="execution(* com.bjpowernode.spring.*.*(..))"/> --> <!-- com.bjpowernode.spring包下所有的类的以add和del开头的方法--> <aop:pointcut id="addAddMethod" expression="execution(* com.angel.spring.*.add*(..)) || execution(* com.angel.spring.*.del*(..))" /> <aop:before method="checkSecurity" pointcut-ref="addAddMethod" /> </aop:aspect> </aop:config> </beans> </span>拦截类:
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.spring; import org.aspectj.lang.JoinPoint; public class SuccessfulHandler { private void checkSecurity(JoinPoint joinPoint) { System.out.println("-------Angel,方法执行成功!-------"); } }</span>
经过这样的配置就可以实现方法的拦截了,但有时候,我们不仅需要拦截方法名称,我们还需要知道,在执行这个方法的时候,用户到底传递了什么样的参数,那么,我们需要在拦截类采用Advice中添加一个JoinPoint参数,取得客户端调用的方法名称及参数值,如:
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.spring; import org.aspectj.lang.JoinPoint; public class SuccessfulHandler { private void checkSecurity(JoinPoint joinPoint) { for (int i=0; i<joinPoint.getArgs().length; i++) { System.out.println(joinPoint.getArgs()[i]); } System.out.println(joinPoint.getSignature().getName()); System.out.println("-------Angel,方法执行成功!-------"); } }</span>
三、采用CGLIB代理
以上的例子,我们都是采用JDK的代理实现的AOP,JDK的动态代理是代理的接口,如果有些类并没有实现接口,那么我们将不得不采用另外一种代理方式:CGLIB动态代理。如:
首先,引入支撑CGLIB的jar包cglib-nodep.jar
其次,在applicationContext配置文件中,强制开启CGLIB代理:
<span style="font-family:KaiTi_GB2312;font-size:18px;"><!-- 强制使用CGLIB代理 --> <aop:aspectj-autoproxy proxy-target-class="true" /></span>
区别:User类不再实现IUser接口,而是一个单独的类,代理成功!
四、总结
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
对于AOP的总结,到此结束,接下来总结事务的知识点。PS:深刻感觉,之前对于AOP是被吓退了!