代理模式是给某个对象提供一个代理对象,并由代理对象控制对原始对象的引用。以下图: java
代理类和委托类有共同的父类,这样在任何使用原始对象(委托对象)的地方均可用代理对象替代。代理对象负责请求的预处理、过滤,将请求分派给原始对象,执行原始对象执行结束后的后续处理。spring
所谓静态代理,是指在程序运行前,就已经存在代理类的字节码文件,代理类和原始类(委托类)的关系在运行前就已肯定。编程
所谓动态代理,是指在程序运行期间,由JVM根据反射机制动态生成代理类的字节码文件,代理类和原始类(委托类)的关系是在运行时肯定的。ide
编写代理模式,便可实现静态代理。但这样的话,有多少个委托类,就须要编写多少个代理类,即便代理逻辑是相同的。而以AspectJ为代理的静态代理,以及JDK动态代理、CGLib动态代理均可以解决这个问题,使得仅需在一个地方编写代理逻辑,这也是AOP思想和目的。工具
AspectJ是Java语言的一个AOP实现,主要包括两个部分:第一个部分定义了如何表达、定义AOP编程中的语法规范,经过这套语言规范,咱们能够方便地用 AOP 来解决Java语言中存在的交叉关注点问题;另外一个部分是工具部分,包括编译器、调试工具等。this
Aspectj实现了独有的编译器,在编译时生成代理类文件。有关AspectJ的用法,参考http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/。代理
Spring AOP的核心就是动态代理。Spring动态代理有两种实现方式:JDK动态代理和CGLib动态代理,Spring会根据实际状况自行选择采用哪一种方式。调试
JDK的动态代理,是基于接口的动态代理。Java API提供以下两个类帮助咱们实现动态代理:code
如下是java动态代理编写示例:对象
/** * 主题接口 */ public interface Subject { public void hello(); }
/** * 委托类或原始类 */ public class DelegateSubject implements Subject { public void hello(){ System.out.println("Hello, Word!"); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 调用处理器,负责实现代理逻辑、转发请求给委托对象 */ public class SubjectInvocationHandler implements InvocationHandler { //代理类持有一个委托类的对象引用 private Object delegate; public SubjectInvocationHandler(Object delegate) { this.delegate = delegate; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long stime = System.currentTimeMillis(); System.out.println(">>begin: "+stime); //利用反射机制将请求转发给委托类处理,method.invoke返回Object对象做为方法执行结果。 //由于委托类的相应方法程序没有返回值,因此这里不处理返回值 method.invoke(delegate, args); long etime = System.currentTimeMillis(); System.out.println(">>end: "+etime); System.out.println("执行任务耗时" + (etime - stime) + "毫秒。"); return null; } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * 生成代理对象的工厂类 */ public class DynProxyFactory { // 客户端调用此工厂方法得到代理对象,它并不知道返回的是代理类对象仍是委托类对象。 public static Subject getInstance() { Subject delegate = new DelegateSubject(); InvocationHandler handler = new SubjectInvocationHandler(delegate); Subject proxy = (Subject) Proxy.newProxyInstance( delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), handler); return proxy; } }
/** * 客户端 */ public class Client { public static void main(String[] args) { Subject proxy = DynProxyFactory.getInstance(); proxy.hello(); } }
尽管java API能够帮助咱们方便的实现动态代理,但因为生成的代理类已经继承了共同的父类(java.lang.reflect.Proxy),这就使得代理类没法再继承其它类,而只能实现接口。也就是说,JDK的动态代理机制只能代理实现了接口的类,而没有实现接口的类就不能代理。
若是要实现对类的动态代理,那就要用CGLib,它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现加强,但由于采用的是继承,因此不能对final修饰的类进行代理。
虽然Spring AOP采用了JDK动态代理和CGLib动态代理,但Spring 容许用AspectJ Annotation来定义方面(Aspect)、切入点(Pointcut)和加强处理(Advice), 而不须要使用AspectJ的编译器和织入器。