定义:为其他对象提供一种代理以控制对这个对象的访问。
UML图:
也可以简单的理解为:
外部表现为通过代理类的对象来进行方法的调用实现功能。其实功能的具体实现是由实现类完成的,代理类对接口的实现上只是对实现类方法的简单调用。
使用场景:当一个对象需要被使用,但是其又不想被直接访问或者无法提供直接访问权限时,即可通过一个代理提供间接访问。
代理模式大致可分为:静态代理和动态代理。其中静态代理实现的关键是:为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。
- 静态代理示例
public interface Subject{
void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
// TODO Auto-generated method stub
System.out.println("RealSubject");
}
}
public class Proxy implements Subject {
private Subject subject = null;
public Proxy(Subject subject) {
super();
this.subject = subject;
}
@Override
public void request() {
// TODO Auto-generated method stub
subject.request();
}
}
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
Subject real = new RealSubject();
Proxy proxy = new Proxy(real);
proxy.request();
}
}
//output
RealSubject
这就好比我们日常中的打官司,由律师出面交涉,但是实际情况还是要依靠当事人的意愿。同时我们注意到 Proxy 持有的是一个 Subject 引用,这就意味着只要是实现了 Subject 的类,都可以去进行代理。而对于 Client 这个使用者来说,他的调用是不变的,从始至终只与代理类打交道。
- 动态代理示例
相比于静态代理,类的代码都是实现编写好后进行调用。动态代理则是通过反射机制动态的生成代理者的对象。实现了在运行阶段确定具体代理的对象是谁。
Java为此提供了一个 InvocationHandler 接口用来快速实现。
public class DynamicProxy implements InvocationHandler {
//被代理的类引用
private Object obj = null;
public DynamicProxy(Object obj) {
super();
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
//调用被代理类对象的方法
Object result = method.invoke(obj, args);
return result;
}
}
此时使用就有所改变了:
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
Subject real = new RealSubject();
//构造动态代理
DynamicProxy dynamicProxy = new DynamicProxy(real);
//获得被代理类的ClassLoader
ClassLoader loader = real.getClass().getClassLoader();
//动态构造一个代理者
Subject real_proxy = (Subject) Proxy.newProxyInstance(loader,
new Class[]{Subject.class}, dynamicProxy);
real_proxy.request();
}
}
在这里我们可以看见 DynamicProxy 类并未像静态代理中样实现和被代理类同样的接口。而是实现了 InvocationHandler 接口的invoke()方法,最后通过
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h)
Parameters:
loader - the class loader to define the proxy class
interfaces - the list of interfaces for the proxy class to implement
h - the invocation handler to dispatch method invocations to
方法来通过反射进行处理。看看该方法的具体实现:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException {
//InvocationHandler不能为空,因为对代理对象的所有方法调用实 //际上都会委托到InvocationHandler的invoke方法,
if (h == null) {
throw new NullPointerException();
}
//这个是核心的地方,通过提供的ClassLoader和interface列表来 //产生代理类
Class cl = getProxyClass(loader, interfaces);
//因为代理类继承了Proxy类.而Proxy中定义了构造函数protected Proxy(InvocationHandler h),所以可以反射得到Constructer实例
//创建代理对象
try {
Constructor cons =
cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
throw new InternalError(e.toString());
}
}
这段代码有待深入研究,以后补充。。。。。
由此可见,代理模式有以下优点:
① 对某些想直接访问存在困难的对象提供一种访问手段。
② 可以实现在实现类的基础上动态的扩展与完善。
③ 代理类与实现类可以是一对多的关系,存在很大的灵活性。