在某种情况下,客户端可能无法或者不愿意直接访问服务器上的对象,比如可恶的中国墙导致必须通过代理才能访问facebook,twitter。
代理模式涉及到三个角色:
抽象角色:声明真实角色的接口;
真实角色:抽象角色的实现;
代理角色:代理角色内可以含有真实角色的引用,同时可以实现一些附加操作。
举个例子:
抽象角色
public interface hello {
public void helloworld();
}
真实角色
public class reallyhello implements hello{
public void helloworld(){
System.out.println("HelloWorld");
}
}
代理角色根据静态代理和动态代理分为不同的两种形式。
静态代理:
静态代理中就是简单地将真实角色中的方法重新实现,重载抽象类中声明的方法。
代理角色
public class helloproxy implements hello{
private hello h;
public helloproxy(hello h){
this.h=h;
}
public void helloworld(){
h.helloworld();
}
}
测试文件
public final class client {
public static void main(String[] args) throws Exception{
reallyhello h = new reallyhello();
helloproxy hp = new helloproxy(h);
hp.helloworld();}
}
静态代理的缺点是代理与真实角色一一对应的,这样对每一个类,都要有一个代理类与之对应,这样代码的复用率就下降,动态代理就很好地解决了该缺点。
动态代理:
Java动态代理主要涉及到两个类:
InvocationHandler:该接口中仅定义了一个Object : invoke(Object proxy, Method method, Object[] args);参数proxy指代理类,method表示被代理的方法,args为method中的参数数组,返回值Object为代理实例的方法调用返回 的值。这个抽象方法在代理类中动态实现。
Proxy:所有动态代理类的父类,提供用于创建动态代理类和实例的静态方法。
所谓动态代理类是在运行时生成的class,在生成它时,你必须提供一组 interface给它,则动态代理类就宣称它实现了这些interface。当然,动态代理类就充当一个代理,你不要企图它会帮你干实质性的工作,在生 成它的实例时你必须提供一个handler,由它接管实际的工作。
代理角色
public class helloproxy implements InvocationHandler{
private Object obj;
public helloproxy(Object h){
this.obj = h;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("before...");
Object ro = method.invoke(obj, args);
System.out.println("after...");
return ro;
}
}
测试文件
public final class client {
public static void main(String[] args) throws Exception{
reallyhello rh = new reallyhello();
InvocationHandler hander = new helloproxy(rh);
hello h = (hello)Proxy.newProxyInstance(rh.getClass().getClassLoader(), rh.getClass().getInterfaces(), hander);
h.helloworld();
}
}
调用顺序如下:
h.helloworld()—>hander.invoke()—>rh.helloworld()
再回过头去看动态代理,用的是最基本的Object类,根本就没有与hello类绑定,因此它可以作为所有从Object衍生出的子类的代理,即一对多的代理,极大地提高了代码的复用率。
动态代理用到的两个文件都位于java的反射包内:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
这种动态代理叫做jdk proxy即原生的jdk代理,它其实也不是完美的,它只能代理实现了接口的类,不能对类本身实现代理,要完成对类本身实现代理,需要用到另外一个开源的类库cglib,这点还有待继续研究。