在上一篇博客中,我们讲了Spring的IOC,下面,我们继续讲解Spring的另一个核心AOP
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP也是Action Oriented Programming 的缩写,意为:面向切面编程,是函数式编程的一种衍生范型。AOP在其他领域也有其他含义。
还是老规矩,站在巨人的肩膀上,看看其他人对AOP的理解:
以上两个例子都是应用JDK动态代理实现的AOP,但是,我们知道Spring给我们提供了两种实现代理的方式,一种是JDK的动态代理,还有一种是CGlib的动态代理,那么,为什么要提供CGlib代理呢?
使用JDK创建代理有一个限制,即它只能为接口创建代理实例,这一点我们可从Proxy的接口newProxyInstance(CIassLoader loader,Class[] interfaces,InvocationHandIer h)的方法签名中就看得很清楚:第二个入参interfaces就是需要代理实例实现的接口列表。虽然而向接口编程的思想被很多大师级人物(包括RodJohnson)推崇,但在实际开发中,许多开发者也对此深感困惑:难道对一个简单业务表的操作也需要老老实实地创建5个类(领域对象类、Dao接口,Dao实现类,Service接口和service实现类)吗?难道不能直接通过实现类构建程序吗?对于这个问题,我们很难给出一个孰好孰劣的准确判断,但我们确实发现有很多不使用接口的项目也取得了非常好的效果(包括大家所熟悉的SpringSide开源项目)。
对于没有通过接口定义业务方法的类,如何动态创建代理实例呢?JDK的代理技术显然己经黔驴技穷,CGLib作为一个替代者,填补了这个空缺。
CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑。
因为和JDK动态代理原理一样,所以这里简单的写一下代理类的实现:
packagecom.proxy.spring; importjava.lang.reflect.Method; importnet.sf.cglib.proxy.Enhancer; importnet.sf.cglib.proxy.MethodInterceptor; importnet.sf.cglib.proxy.MethodProxy; publicclass CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz){ enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Methodmethod, Object[] args, MethodProxy proxy) throws Throwable{ System.out.println(obj.getClass().getName()+"."+method.getName()); Objectresulet=proxy.invokeSuper(obj,args); System.out.println("========end==================="); return resulet; } }
JDK和CGlib除了在是否使用接口上的差异以外,在性能上也有一定的差异,理解这些差异,可以让我们更好的使用它们:
JDK动态代理所创建的代理对象,在JDK1.3下,性能强差人意,虽然在高版本的JDK中,动态代理对象的性能得到了很大的提高,但是有研究表明,CGLib所创建的动态代理对象的性能依旧比JDK的所创建的代理对象的性能高不少(大概10倍)。但CGLib在创建代理对象时所花费的时间却比JDK动态代理多(大概8倍),所以对于singleton的代理对象或者具有实例池的代理因为无须频繁创建代理对象,所以比较适合用CGLib动态代理技术,反之适合用JDK动态代理技术,值得一提的是,由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行代理。
但是,以上我们说来说去,一直在说动态代理,虽然动态代理实现了AOP,但是,我们想一下我们实际的应用,就会发现有很多问题,当然,Spring AOP就是基础这些问题创建的:
1)目标类的所有方法都添加了性能监视横切逻辑,而有时,这并不是我们所期望的,我们可能只希望对业务类中的某些特定方法添加横切逻辑;
2)我们通过硬编码的方式指定了织入横切逻辑的织入点,即在目标类业务方法的开始和结東前织入代码;
3)我们手工编写代理实例的创建过程,为不同类创建代理时,需要分别编写相应的程序代码,无法做到通用。
以上三个问题,在AOP中占用重要的地位,因为SpringAOP的主要工作就是围绕以上三点展开;SpringAOP通过Pointcut(切点)指定在哪些类的哪些方法上织入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前、方法后、方法的两端等)。此外,Spring通过Advisor(切面)将Pointcut和Advice两者组装起来。有了Advisor的信息,Spring就可以利用JDK或CGLib的动态代理技术采用统一的方式为目标Bean创建织入切面的代理对象了。
在Spring容器里,我们可以发现,Spring容器包含各种增强类,比如前置增强,后置增强,环绕增强等,还有各种切点,切面,以解决上述动态代理所存在的一些问题,其实如何解决这些问题我们暂且不研究(研究起来可能就不是一篇博客可以写得完的了),总之,Spring已经把这些类都已经写好了,现在要使用这些东西,比如我们需要在一个add方法前面插入验证,那么我们应该怎么做呢?如果我们没有接触过Spring,一定会这样想,那就在和之前使用JDK或者CGlib动态代理一样直接调用不就好了吗:
MyProxy hander = new MyProxy(); Animal dog = (Animal)hander.createProxyInstance(new Dog()); dog.run(); dog.jump();
这里我们很容易发现,代理已经和被代理的类耦合在一起了,这里我们就发现,我们伟大的IOC就需要出现来了,我们只需要把他们交给第三方来实现解耦合就可以了。
其实,最后这段话是我之前一直都没有想过的,因为之前一直在强调Spring的核心是IOC和AOP,只是在想IOC是什么?AOP是什么?从来没有把他们关联起来想,其实,从这里我们就可以看出,Spring的AOP其实是构建于IOC之上,和IoC浑然天成统一于Spring的容器之中,也就是说,如果没有Spring IOC,AOP是无法发挥他的强大的作用的,当然,如果没有Spring AOP,IOC还是有很多问题无法解决,同时,我们在想一下Spring的其他技术,比如事务,我们应该对事务比较清楚,Spring的事务就是被AOP到Spring中的,当然,还有比如对比如JDBC、Hibernate等的集成其实都是在Spring IOC的基础上开花结果的。其实如果这样想下去,Spring的学习,就变成使用IOC或者AOP对已经存在的类的整合,随便什么类,反正拿过来控制依赖注入一下,或者是当切进去就可以为我们所用了,如果从这个角度看Spring,是不是就发现Spring变得简单而强大了!
原文:http://blog.csdn.net/laner0515/article/details/38303677