代理设计模式再生活中应该很常见了,如今各类中间商的货物代售方便了咱们的生活也增长了咱们生活的成本。这种生活中的中间商行为就是一种代理模式。java
拿一个品牌来讲明:编程
在编程领域中通常存在两种代理模式设计模式
接下来咱们先来看静态代理ide
仅仅用来代理一个类的行为。函数
代码演示一下:工具
class NaiKe { void run() { System.out.println("耐克"); } } //代理类 class ShoesProxy extends NaiKe{ @Override void run() { System.out.println("agency shoes before"); super.run(); System.out.println("agency shoes after"); } }
class NaiKe{ void run() { System.out.println("耐克"); } } class ShoesProxy { NaiKe naiKe = new NaiKe(); void run() { System.out.println("agency shoes before"); naiKe.run(); System.out.println("agency shoes after"); } }
public class ProxyDesgin { public static void main(String[] args) { Shoes shoes = new ShoesProxy(new ShoesTimer(new NaiKe())); shoes.run(); } } abstract class Shoes{ abstract void run(); } class NaiKe extends Shoes{ @Override void run() { System.out.println("耐克"); } } class Adi extends Shoes{ @Override void run() { System.out.println("阿迪达斯"); } } //代理类 class ShoesProxy extends Shoes { Shoes shoes ; public ShoesProxy(Shoes shoes){ this.shoes = shoes ; } void run() { System.out.println("agency shoes before"); shoes.run(); System.out.println("agency shoes after"); } } class ShoesTimer extends Shoes { Shoes shoes ; public ShoesTimer(Shoes shoes){ this.shoes = shoes ; } void run() { System.out.println("log timer shoes before"); shoes.run(); System.out.println("log timer shoes after"); } }
画个图瞅瞅静态代理this
这个就是静态代理,兄弟们应该已经发现了它的缺点,只能指定本身想要进行代理的类,而不能对全部的类进行代理,扩展性太差,因此引出了动态代理设计
谈到动态代理,脑子里第一个出现的确定就是Java
动态代理了。咱们先来聊一下Java
动态代理。代理
先来看一个动态代理的案例code
NaiKe naiKe = new NaiKe(); Shoes shoes = (Shoes) Proxy.newProxyInstance(NaiKe.class.getClassLoader(), new Class[]{Shoes.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("begin timer : " + System.currentTimeMillis()); method.invoke(naiKe,args); System.out.println("after timer : " + System.currentTimeMillis()); return null; } }); shoes.run();
咱们看一下动态代理的源码。
咱们能够经过如下方式让JVM
将动态生成的代理类保存到咱们的项目中
JDK1.8
使用System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
JDK1.8
以上能够使用1 System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
生成的代理类以下:
final class $Proxy0 extends Proxy implements Shoes { 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 { } public final void run() throws { try { 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 { } public final int hashCode() throws { } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("desgin.proxy.Shoes").getMethod("run"); 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()); } } }
从这个类的结构中,咱们能够看出不少的东西
JAVA
动态代理仅仅只能代理接口。(类单继承,代理对象默认继承Proxy类)invoke
方法。上面两个也是动态代理的原理了。咱们来仔细看一下咱们的run()
方法,也就是咱们代理对象要实现的接口
public final void run() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }
h
,父类的h
是InvocationHandler
,而后调用了invoke
方法执行了咱们的执行逻辑。这个就是动态代理的所有实现过程
还有一个很是牛逼的点,它怎么生成的这个代理类。来看一下代理的全过程
图中的ASM
就是为咱们动态生成一个代理类的工具,它直接操做了Class
字节码的二进制,而后建立了一个代理类,返回给咱们。
Java
动态代理就聊到这里了。下面看一看CGLIb
和AOP
弥补了Java
动态代理的不足,CGLIB
动态代理能够代理类。它直接建立了一个被代理对象的子类,实现了对其的代理过程。咱们来看一下它的代理过程
//打印生成的代理对象,放置于当前项目下 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "."); //建立Enhancer对象,相似于JDK动态代理的Proxy类,下一步就是设置几个参数 Enhancer enhancer = new Enhancer(); //设置目标类的字节码文件 enhancer.setSuperclass(Tank.class); //设置回调函数 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { methodProxy.invokeSuper(o,objects); return null; } }); //这里的creat方法就是正式建立代理类 Tank proxyDog = (Tank)enhancer.create(); //调用代理类的eat方法 proxyDog.tank();
仍是和Java
动态代理类似,传入一个须要代理的Class
,设置代理的回调函数。而后调用create
建立一个代理对象,调用代理对象的方法。
代理第一行能够输出代理对象,会生成三个代理对象。
查看中间那个,能够看到咱们被代理对象的方法
public class Tank$$EnhancerByCGLIB$$a4ec679a extends Tank implements Factory { //构造方法 public Tank$$EnhancerByCGLIB$$a4ec679a() { CGLIB$BIND_CALLBACKS(this); } //被代理方法 final void tank() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { //调用加强的方法 var10000.intercept(this, CGLIB$tank$0$Method, CGLIB$emptyArgs, CGLIB$tank$0$Proxy); } else { super.tank(); } } }
在以前的CGLIB
动态代理实现中,咱们看到了拦截的回调中传入了四个参数,从上面的源码中能够看到对应参数的做用。
Object o
表明生成的代理对象Method method
表明当前代理对象调用的方法Object[] objects
表明方法的参数MethodProxy methodProxy
咱们调用方法的方法代理,它没有使用Java
自己的反射,而是动态生成一个新的类,(继承FastClass
),向类中写入委托类实例直接调用方法的语句。咱们能够看一下superinvoke
的源码
public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { this.init(); MethodProxy.FastClassInfo fci = this.fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException var4) { throw var4.getTargetException(); } } private static class FastClassInfo { FastClass f1; FastClass f2; int i1; int i2; private FastClassInfo() { } }
一个图理解CgLib
动态代理过程
写了这么多,感受对于代理设计模式讲解的篇幅不是很大,而是着重讲解了动态代理的实现方式。总的而言,代理设计模式与咱们平常生活很是的接近,生活中的事物几乎都在被代理,因此这个设计模式应该很好懂,因此着重讲解了动态代理的实现方式。