代理模式在生活中的应用常见随处可见,例如:快递员、中介、媒婆、黄牛等等。代理模式可以实现AOP,拦截器,代码解耦等功能。一般有3中实现方式:
- 静态代理
- JDK实现的动态代理(创建目标对象的所有接口的代理实现类)
- CGLIB实现的动态代理(创建目标对象的代理子类)
实现代理模式,代理对象需要拿到目标对象的引用且能够调用目标对象的方法。当然也有些代理不需要目标对象的引用,例如Mybatis的Mapper代理对象就不需要目标对象,不过Mapper也没有具体实现的类。
1.静态代理
这种代理实现的功能比较单一,因为在代理运行前,目标对象是明确的(类型明确),同时也不易扩展,扩展时需要同时改造目标类和代理类,不遵守开闭原则。属于需要人工干预的代理,不具有智能自动化,一般很少使用。
2.动态代理(JDK)
动态代理在运行前,所有的东西都是未知的,只有到运行时才知道,容易扩展。属于智能自动化的代理,应用的比较广泛。
使用JDK实现的动态代理代码:
package com.kancy.pattern.proxy; import pattern.ApplePhone; import pattern.Phone; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JDKDynamicProxy<T> implements InvocationHandler { private T target; public JDKDynamicProxy() { } public JDKDynamicProxy(T target) { this.target = target; } public T getProxyObject(){ return (T) Proxy.newProxyInstance( target.getClass().getClassLoader() //加载动态生成的class到JVM ,target.getClass().getInterfaces() //代理对象需要实现的接口 ,this // 代理对象具体代理实现,这里为了方便,使用当前类 ); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理处理------------start"); Object invoke = method.invoke(target, args); System.out.println("代理处理------------end"); return invoke; } public static void main(String[] args) { // 手机Phone接口类型的代理 JDKDynamicProxy<Phone> proxy = new JDKDynamicProxy(new ApplePhone()); Phone proxyObject = proxy.getProxyObject(); proxyObject.getName(); } }
原理解析:(字节码重组)
- 拿到目标对象的引用,并获取他的所有接口和类加载器
- 使用sun.misc.ProxyGenerator类生成一个实现了目标对象所有接口的实现类(java源码),并且动态编译成class字节码数组。
- 生成类的格式:目标类名.$Proxy{序号n}
- 使用目标对象的类加载器,把编译后的字节码加载到JVM使用。
- 删除代理创建过程中的产生的class文件。
/* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); }
3.动态代理(CGLIB)
CGLIB实现的动态代理与JDK实现的动态代理,不同点在于CGLIB动态生成的是目标对象的子类,而JDK动态生成的是目标对象所有接口的实现类,其他原理基本类似。
使用CGLIB实现的动态代理代码:
package com.kancy.pattern.proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import pattern.ApplePhone; import java.lang.reflect.Method; public class CGLIBDynamicProxy<T> implements MethodInterceptor { private T target; public CGLIBDynamicProxy() { } public CGLIBDynamicProxy(T target) { this.target = target; } public T getProxyObject(){ Object proxy = Enhancer.create(target.getClass(), this); return (T) proxy; } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("代理处理------------start"); Object invoke = method.invoke(target, objects); System.out.println("代理处理------------end"); return invoke; } public static void main(String[] args) { ApplePhone target = new ApplePhone();//目标对象 CGLIBDynamicProxy<ApplePhone> proxy = new CGLIBDynamicProxy(target); ApplePhone proxyObject = proxy.getProxyObject(); proxyObject.getName(); } }
Enhancer.create()代码:
public static Object create(Class type, Callback callback) { Enhancer e = new Enhancer(); e.setSuperclass(type); e.setCallback(callback); return e.create(); }
在附上sun.misc.ProxyGenerator创建Class字节码代码:
package com.kancy.pattern.proxy; import pattern.ApplePhone; import sun.misc.ProxyGenerator; import java.io.FileOutputStream; import java.io.IOException; public class ProxyGeneratorTest { public static void main(String[] args) throws IOException { // 生成ApplePhone类的代理类CLASS文件 byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", ApplePhone.class.getInterfaces()); FileOutputStream out = new FileOutputStream("$Proxy0.class"); out.write(bytes); out.close(); } }
创建的class反编译代码:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import pattern.Phone; public final class $Proxy0 extends Proxy implements Phone { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String getName() throws { try { return (String)super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("pattern.Phone").getMethod("getName"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }