为其余对象提供一种代理以控制对这个对象的访问。java
按照代理建立的时期来进行分类的话, 能够分为两种:静态代理、动态代理。静态代理是由程序员建立或特定工具自动生成源代码,在对其编译。在程序员运行以前,代理类.class文件就已经被建立了。动态代理是在程序运行时经过反射机制动态建立的。程序员
静态代理在使用时,须要定义接口或者父类,被代理对象与代理对象一块儿实现相同的接口或者是继承相同父类。缓存
实现工具
这里假设Tom要买一套房子,而后本身没有足够的资金,因而就让他的父亲代理他来给他买下这套房子。性能
买房子接口:测试
public interface BuyHouse { void Buy(); }
Tom类:this
public class Tom implements BuyHouse { public void Buy() { System.out.println("Tom买到房子了..."); } }
Father类:设计
public class Father implements BuyHouse { private Tom tom; public Father(Tom tom){ this.tom = tom; } public void Buy() { System.out.println("Father给Tom买了房子..."); tom.Buy(); } }
静态代理的优缺点:代理
动态代理日志
下面咱们使用JDK动态代理的方式来对上面的静态代理示例进行改写
买房子接口和Tom类都和上面的同样
建立代理类JdkProxy:
public class JdkProxy implements InvocationHandler { private Object target; //接收被代理的目标对象对象 public JdkProxy(Object target){ this.target = target; } //生成目标对象的代理对象 public Object getProxyInstance(){ Object instance = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); return instance; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始Jdk动态代理,来给Tom买房子"); //执行目标对象的方法 Object returnVal = method.invoke(target,args); return returnVal; } }
测试类:
public class testJdkProxy { @Test public void test(){ BuyHouse tom = new Tom(); JdkProxy jdkProxy = new JdkProxy(tom); BuyHouse proxyInstance = (BuyHouse)jdkProxy.getProxyInstance(); proxyInstance.Buy(); } } /**测试结果 开始Jdk动态代理,来给Tom买房子 Tom买到房子了... */
注意Proxy.newProxyInstance()方法接受三个参数:
静态代理和JDK代理模式都要求目标对象实现一个接口,可是有时候目标对象只是一个单独的对象,并无实现任何对象,这个时候可使用目标对象的子类来实现代理,这就是Cglib代理。
CGLib采用了很是底层的字节码技术,其原理是经过字节码技术为一个类建立子类,并在子类中采用方法拦截的技术拦截全部父类方法的调用,顺势织入横切逻辑。但由于采用的是继承,因此不能对final修饰的类进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
实现
建立没有实现接口的Tom类:
public class Tom { public void Buy() { System.out.println("Tom买到房子了..."); } }
建立Cglib代理类:
public class CglibProxy implements MethodInterceptor { private Object target; public Object getProxyInstance(Object target){ this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); return enhancer.create(); } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("开始Cglib代理,来给Tom买房子"); Object returnVal = method.invoke(target, objects); return returnVal; } }
建立测试类:
public class testCglibProxy { @Test public void test(){ Tom proxyInstance = (Tom) new CglibProxy().getProxyInstance(new Tom()); proxyInstance.Buy(); } } /**测试结果 开始Cglib代理,来给Tom买房子 Tom买到房子了... */
CGLIB代理总结: CGLIB建立的动态代理对象比JDK建立的动态代理对象的性能更高,可是CGLIB建立代理对象时所花费的时间却比JDK多得多。因此对于单例的对象,由于无需频繁建立对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时因为CGLib因为是采用动态建立子类的方法,对于final修饰的方法没法进行代理。