1 介绍
为其他对象提供一个代理以控制对某个真实对象的访问,如Spring的AOP,Nginx的反向代理和Hibernate中PO(Persistant Object 持久化对象)字节码的生成等。优点可以降低系统的耦合度,缺点是需要额外的工作,而且有些代理模式的实现比较复杂。根据代理的创建时期,可划分为静态代理和动态代理两种。
2 静态代理
在程序运行前代理类的.class文件就已经存在了。
2.1 UML图分析
GoogleSearch是一个公共的接口,通过其实现海外服务器ForeignDerver可以直接访问谷歌搜索,类ProxyServer虽然也是GoogleSearch接口的实现,但实际上是用户侧的代理服务器,它可以从ForeignDerver处间接访问谷歌搜索。类StaticProxyDemo是测试类。
2.2 源码
1)创建公共接口
2)接口实现类
public class ForeignServer implements GoogleSearch {
@Override
public void useGoogleSearch() {
System.out.println("Connect successfully!");
}
}
3)代理类
public class ProxyServer implements GoogleSearch {
private ForeignServer foreignServer;
@Override
public void useGoogleSearch() {
if(foreignServer == null){
foreignServer = new ForeignServer();
}
foreignServer.useGoogleSearch();
}
}
4)测试类
public class StaticProxyDemo {
public static void main(String[] args) {
GoogleSearch googleSearch = new ProxyServer();
googleSearch.useGoogleSearch();
}
}
2.3 测试结果
2.4 缺点
如果要想为多个类进行代理,则需要建立多个代理类,维护难度加大。通俗得讲,此时的代理服务器是专有服务器,只能用于访问谷歌相关产品,那么要访问FB的产品又需要不同的代理服务器,这样下来就需要一大堆海外服务器。
3 动态代理
动态代理是在程序运行时运用反射机制动态创建而成。相对于静态代理,其只需要一个代理类即可,即只需要一个通用服务器即可访问n多海外网站。
3.1 UML图分析
相对静态代理,ProxyServer只需要实现InvocationHandler接口。getProxy()方法是利用反射技术,在JVM运行时获取一个实现了指定接口的代理类的实例。而invoke()是在代理实例上处理方法调用并返回结果。
3.2 源码
1)创建接口
2)接口实现类
public class ForeignServer implements GoogleSearch {
@Override
public void useGoogleSearch() {
System.out.println("Connect successfully!");
}
}
3)代理类
public class ProxyServer implements InvocationHandler {
private Object obj;
public ProxyServer(Object obj) {
this.obj = obj;
}
/**
* 返回一个实现了指定接口的类的实例
* @return
*/
public Object getProxy(){
return Proxy.newProxyInstance(Thread.currentThread()
.getContextClassLoader(), obj.getClass().getInterfaces(), this);
}
/**
* 在代理实例上处理方法调用并返回结果
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(obj, args);
return result;
}
}
4)测试类
public class DynamicProxyDemo {
public static void main(String[] args) {
GoogleSearch foreignSearch = new ForeignServer();
ProxyServer proxyServer = new ProxyServer(foreignSearch);
GoogleSearch proxySerch = (GoogleSearch)proxyServer.getProxy();
proxySerch.useGoogleSearch();
}
}
3.3 测试结果
3.4 缺点
Java动态代理要求被代理的类必须实现接口,有很强的局限性,可以通过CGLIB动态代理的方式解决。