代理可以分为:静态代理(StaticProxy)和动态代理(DynamicProxy)
为某个对象提供一个代理,以控制这个对象的访问。代理类和委托类有共同的父类和父接口,这样在任何使用委托类对象的地方都可以使用代理对象代替。代理类负责请求的预处理、过滤、将请求分派给委托类处理以及委托类执行完请求后后的后续处理。代理分为了静态代理和动态代理。
个人感觉代理这种模式汲取了继承和组合的优点,即没有暴露委托类的任何敏感信息,又能通过运用组合来实现较多的功能。至于委托类和代理类实现共同的接口(也就是所谓的代理接口),目的是为了让用户用起来觉得根本不存在中间的代理类。(就好像一些中介机构做的很隐蔽,让用户和主人之间感觉没有第三方一样)。
图解中的Client即调用接口的一方,代理接口(Subject)、委托类(RealSubject)、代理类(ProxySubject),通过代理类来和用户交流。下面用一个小故事来说明代理模式:A君有一套房子需要出售,由于买家不好找就直接挂在了B君的代售公司,过一段时间买家C君直接就把房子买走了。看下面的代码实现:
interface sell {
public void sellHouse();
}
class PersonA implements sell{
public void sellHouse() {
System.out.println("RealSubject...SellHouse...");
}
}
class PersonB implements sell{
//代理君B持有一个真实类(房主A)的实例,可以想象类似成留了一个电话号码,有人来买房子就立马通知
PersonA a = new PersonA();
public void sellHouse() {
//有人来买房就立马通知真实类(房主A)...
a.sellHouse();
System.out.println("Proxy...SellHouse...");
}
}
public class JavaTest{
public static void main(String[] args) {
//我就相当于是买房子的C君
PersonB b = new PersonB();
//我直接找代理B君买房子
b.sellHouse();
}
}
运行结果为:
RealSubject...SellHouse...
Proxy...SellHouse...
至于真实类和代理类需要实现同样的一个接口,小达认为统一接口能让客户端在用到真实类对象的地方都能够替换成代理类,不用改变其调用的方法。因为在这里调用类完全不可以实现接口,利用组合的特性持有真实类的对象,通过自定义几个方法直接调用真实类的方法,这样暴露给外界的接口即是代理类自定义的一些接口了。
JDK 5中引入的动态代理机制,允许开发人员在运行时刻动态的创建出代理类及其对象。在运行时刻,可以动态的创建出一个实现了多个接口的代理类。
说道动态代理,就不得不涉及到java.lang.reflect.Proxy类,这是Java动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态的生成代理类及其对象。
每个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接口的实现。使用者调用了代理对象所代理的接口中的方法的时候,这个调用的信息会被传递给InvocationHandler的invoke方法。在invoke方法的参数中可以获取到代理对象、方法对应的Method的对象和调用的实际参数,最后invoke方法执行的结果将被返回给调用者。这种做法实际上是对方法调用的拦截。
简单的来说,真实类在运行之前都不知道自己的代理类是谁,在运行期间通过反射来动态的生成一个代理类并为真实类做代理。下面又有个小故事(纯属虚构,小朋友们不要学坏…..)来辅助理解:A君(真实类)马上要考试了,但自己实力不够,于是想找人代考(即找自己的代理类,在找到之前不知道自己的代理类是谁),接着通过B君(相当于InvocationHandler,用于分发调用请求)的介绍,找到了一只学霸君(相当于动态生成的代理类,并不知道是谁)帮助代考。实现的代码如下:
interface Exam {
public void findHelp();
}
class PersonA implements Exam{
public void findHelp() {
System.out.println("PersonA...find...help...");
}
}
/**
* 这个类就相当于是B君,为A君动态的创建代理类对象
*/
class MyInvocationHandler implements InvocationHandler {
private Object targetObject;
public Object newProxyInstance(Object o) {
//targetObject是真实类的对象,就相当于是A君
targetObject = o;
/*
* 在这里动态的为传入的真实对象o动态的创建了一个代理类,也就是我们说的学霸君
* 最后一个参数this指的是处理调用拦截的Handler
*/
return Proxy.newProxyInstance(
targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),
this);
}
/**
* 在调用的时候拦截调用方法,然后做相的处理
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.invoke(targetObject, args);
}
}
public class JavaTest{
public static void main(String[] args) {
PersonA a = new PersonA();
MyInvocationHandler mih = new MyInvocationHandler();
//为A君动态生成代理类
Exam e = (Exam) mih.newProxyInstance(a);
e.findHelp();
}
}