代理模式是二十多种设计模式中的一个,属于比较经常使用的设计模式。本质上就是用来委托咱们生成的代理类去完成一些额外的功能,这样可以达到解耦、封装的目的。
一般能够用在RPC、AOP中。好比在RPC中,当咱们调用远程方法时,须要委托代理类帮助咱们去经过网络链接远程的服务提供者,帮助咱们将消息编码发送给服务端,帮咱们接受服务端发来的结果。java
在代理模式中,一般指的时静态代理。设计模式
这是静态代理的UML图。代理的思想是:代理类ProxySubject拥有实际类RealSubject的相同方法doSomething(实现相同的一个接口),同时代理类内聚了实际类(即传入实际类的一个引用),在代理类的doSomething方法中,经过实际类的引用调用实际类的doSomething方法,并在调用先后加入须要代理实现的额外功能。这样咱们就能够经过调用代理类的相同方法来达到咱们的目的。
举个例子:网络
interface Subject{ void doSomething(); }
class RealSubject implements Subject{ void doSomething(){ System.out.println("doSomething"); } }
class ProxySubject implements Subject{ private Subject target; public ProxySubject(Subject target){ this.target = target; } void doSomething(){ //do before System.out.println("do before"); target.doSomething();//调用realSubject的doSomething方法 //do after System.out.println("do after"); } }
class ProxyTest{ public static void main(String args[]){ //生成代理类,并将实际类传入 ProxySubject proxy = new ProxySubject(new RealSubject()); proxy.doSomething(); } }
以上,经过代理类执行实际类相同的方法,咱们能够运行额外的功能。这里不只会运行实际类doSomething方法里面的打印“doSomething”,还会在以前打印“do before",以后打印”do after",这两个即为额外的功能。框架
上面的静态代理其实存在一个问题,一个实际类对应一个代理类,而不少时候须要代理实现的额外功能是相同的,好比咱们要在A类的某个方法调用前打印“before”,B类的某个方法调用前打印“before”,C类也有这个需求,若是用静态代理,咱们须要写A类的代理,B类的代理,C类的代理。。。这样岂不是要累死。
java当中的动态代理就是为了这个解决这个问题。其实思路也很简单,不用去管A类、B类、C类仍是什么其余类,统一用反射调用实际类的方法。
java提供了动态代理类Proxy,使用其中的静态方法Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)来动态生成代理类。interfaces为实际类的接口,对应上面图中的Subject,loader为接口的Classloader,InvocationHandler接口有一个invoke方法须要本身实现,咱们委托代理类实现的额外功能便放在该方法里。须要注意的是由此看出java的动态代理须要有接口才能使用。若是不用接口实现动态代理只能求助于cglib这类字节码加强框架。
下面是动态代理的通常实现方法:ide
public class InvokeProxy implements InvocationHandler{ private Object target; public Object bind(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("do something before"); method.invoke(target, args); System.out.println("do something after"); return null; /* 若是反射调用的方法有返回值: Object result; result = method.invoke(target, args); return result; */ } }
一样有接口Subject:this
interface Subject{ void doSomething(); }
假设类A实现了Subject接口,能够根据以下代码生成A的代理编码
public class ProxyTest { public static void main(String[] args) { Subject proxyA = (Subject)new InvokeProxy().bind(new A()); proxyA.doSomething(); } }
若是还有类B实现了Subject接口,咱们只需更改上面的代码便可,而不用像静态代理那样重复的编写代码。这就是动态代理相对于静态代理的意义。spa