代理模式是二十多种设计模式中的一个,属于比较常用的设计模式。本质上就是用来委托我们生成的代理类去完成一些额外的功能,这样能够达到解耦、封装的目的。
通常可以用在RPC、AOP中。比如在RPC中,当我们调用远程方法时,需要委托代理类帮助我们去通过网络连接远程的服务提供者,帮助我们将消息编码发送给服务端,帮我们接受服务端发来的结果。
静态代理
在代理模式中,通常指的时静态代理。
这是静态代理的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这类字节码增强框架。
下面是动态代理的一般实现方法:
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:
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接口,我们只需更改上面的代码即可,而不用像静态代理那样重复的编写代码。这就是动态代理相对于静态代理的意义。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。