3.4 Spring AOP
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB
AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:
1、定义普通业务组件
2、定义切入点,一个切入点可能横切多个业务组件
3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作
所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。

Spring AOP 实例
下面的代码中我们省去了UserDao.java接口和UserDaoImpl.java类,读者可以自行添加。
package aspect; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class MyAspect implements MethodInterceptor{ public void checkManager(){ System.out.println("验证管理员身份!"); } public void log(){ System.out.println("添加操作记录到数据库!"); } @Override public Object invoke(MethodInvocation arg0) throws Throwable { checkManager(); Object obj=arg0.proceed(); log(); return obj; } } |
MyAspect类实现了MethodInterceptor接口,这使它能够具有处理旧类和新类,使得旧类中的方法具有更强的功能,其代码中实现了invoke方法,该方法的参数就是提供要处理的旧类中的方法的对象。我们可以在该方法执行的前后进行代码增强。
在下面的配置文件中我们使用到了一个重要的类:org.springframework.aop.framework.ProxyFactoryBean,以下是该类的几个常用配置属性。
1、 target:代理的目标对象
2、 proxyInterface: 代理所需要的实现的接口,可以是多个接口,该属性还有一个别名属性interfaces.
3、 interceptorNames: 需要植入的目标对象的Bean列表,采用Bean的名称指定,这些Bean必须是实现了org.aopalliance.intercepr.MethodInterceptor 或者org.sorngframework.aop.Advisor的bean,配置中的顺序对应调用的顺序
4、 singleton:返回的代理对象是否单例,默认是单例
5、 optimize: 当设置为true时 ,强制使用cglib代理,对于singleton的代理,我们推荐使用cglib代理,对于其他类型的代理,最好使用JDK代理,原因是cglib创建代理时速度慢,而创建出的代理对象运行效率较高,而使用JDK代理的表现正好相反。
6、 proxyTargertClass: 是否对类进行代理(而不是对接口进行代理)。设置为true时,使用cglib代理。
使用 ProxyFactoryBean 来创建 AOP 代理的最重要的优点之一是 IoC 可以管理通知和切入点。 这是一个非常的强大的功能,能够实现其他 AOP 框架很难实现的特定的方法。这是创建AOP的最基本的方式 。
下面就是本案例的配置文件。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> <!-- 将指定类配置给Spring,让Spring创建其对象的实例 --> <bean id="userDao" class="impl.UserDaoImpl"></bean> <bean id="myAspect" class="aspect.MyAspect"></bean> <bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="dao.UserDao"></property> <property name="target" ref="userDao"></property> <property name="interceptorNames" value="myAspect"></property> <property name="proxyTargetClass" value="true"></property> </bean> </beans> |
在上述配置文件中我们配置了ProxyFactoryBean类的四个属性,其中<property name="proxyInterfaces" value="dao.UserDao">代码说明要代理的是满足dao.UserDao接口要求的类,<property name="target" ref="userDao">代码说明要代理的旧类对象,<property name="interceptorNames" value="myAspect">代码说明要使用的含有新功能的新类对象。
测试类代码如下:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import dao.UserDao; import impl.UserDaoImpl; public class Test { public static void main(String[] args) { ApplicationContext appc=new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao ud=(UserDao)appc.getBean("userDaoProxy"); ud.delUser(); ud.addUser(); } } |
在测试类中我们并不是直接使用UserDao的子类对象,而是使用代理类。从下面的程序运行结果可以看出,旧类中的方法功能被正确的增强了。
验证管理员身份! 删除用户! 添加操作记录到数据库! 验证管理员身份! 添加用户! 添加操作记录到数据库! |

