概述
代理模式为一个对象提供一个替身以控制对这个对象的访问。其实就是代理就是做到类似转发的功能,针对不同代理,转发的具体实现不同。从原理知道他就是控制客户对一个对象的访问,它跟现实中的中介代理类似,只是作为代表做一些受理工作,真正执行的并不是它自己。
结构图
解析:被代理类 和 代理类实现同一个接口,通过代理类的对象来访问被代理的对象。
应用实例
在这个例子中,主要讲解远程代理,它可以作为另一个JVM上的本地代表。客户端调用代理的方法,代理会利用网络把请求转发到远程执行,并把执行结果通过网络返回到代理,最终返回到客户端。
下面使用引用java RMI(Remote Method Invoke远程方法调用)的例子讲解远程代理模式。它的的工作原理图如下,用户向服务器A发起话费充值请求,服务器A通过网络调用服务器B的方法,服务器B把充值结果返回到服务器A,最后返回到用户。
代码实现如下,首先创建一个远程接口
package com.jet.pattern.proxy;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* description:
* 远程接口,其继承java的Remote接口,真正干活对象和代理都要实现这个接口
* Created by Administrator on 2017/1/17.
*/
public interface MyRemote extends Remote{
// 远程调用有风险告诉客户端
public String request(int money) throws RemoteException, MalformedURLException, NotBoundException;
}
创建远程对象
package com.jet.pattern.proxy.impl;
import com.jet.pattern.proxy.MyRemote;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
/**
* description:
* 真正干活的对象,接受代理对象的访问
* Created by Administrator on 2017/1/17.
*/
// 继承UnicastRemoteObject,让jvm帮我们完成远程调用
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{
// 父类构造器抛出了异常,所以子类构造器也需要抛出异常
public MyRemoteImpl() throws RemoteException {
}
@Override
public String request(int money) throws RemoteException {
System.out.println("充值" + money + "元话费成功");
return "充值成功";
}
public static void main(String[] args) {
try {
// 产生远程对象
MyRemote service = new MyRemoteImpl();
// 注册远程访问接口
LocateRegistry.createRegistry(8888);
// 注册远程对象,注册名为RemoteHello,代理访问时指定这个名称就可以找到本类,
Naming.rebind("rmi://localhost:8888/RemoteHello",service);
} catch (Exception e) {
e.printStackTrace();
}
}
}
创建代理对象
package com.jet.pattern.proxy.impl;
import com.jet.pattern.proxy.MyRemote;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
/**
* description:
* 代理对象,控制客户端的访问,把客户端访问请求转发到真正干活的对象
* Created by chenzanjin on 2017/2/4.
*/
public class Proxy implements MyRemote {
@Override
public String request(int money) throws RemoteException, MalformedURLException, NotBoundException {
MyRemote remote = (MyRemote)Naming.lookup("rmi://localhost:8888/RemoteHello");
return remote.request(money);
}
}
创建访问客户端
package com.jet.pattern.proxy.test;
import com.jet.pattern.proxy.MyRemote;
import com.jet.pattern.proxy.impl.Proxy;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
/**
* description:
* 代理客户端,测试对代理的访问
* Created by chenzanjin on 2017/2/4.
*/
public class ProxyClient {
public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {
MyRemote proxy = new Proxy();
System.out.println(proxy.request(100));
}
}
测试步骤:
1、启动MyRemoteImpl 类的main方法,绑定远程对象到jvm。
2、启动ProxyClient 类的main方法,对代理对象发起访问。
代码输出如下:
MyRemoteImpl 类会输出:充值100元话费成功
ProxyClient 类输出:充值成功
其他代理
1、虚拟代理:可以作为创建开销大的对象的代表,虚拟代理让我们真正需要使用一个对象时才会去创建这个对象。在对象创建前和创建中,虚拟代理扮演真实对象的替身,当对象创建完毕后,虚拟代理会把请求直接委托给真实对象。虚拟代理在手机页面加载中经常可以见到,比如打开页面显示"**正在玩命加载中..."。
2、缓存代理:可以理解成把网络上的静态资源或者不常改变的数据保存在本地,再次访问的这次数据的时候直接从本地读取。应用例子有页面的缓存机制、cdn、app缓存机制等。
3、保护代理:根据角色或者其他机制控制用户对一些资源的访问权限。这常见于一些网站需要登录才能获取更多的内容,struts2和spring的拦截器等。
4、静态代理:可以理解为对象由代理创建,在创建前后做一些事情,比如统计创建了多少对象,但静态代理只能创建一个或固定的几个对象。详见:http://blog.csdn.net/lidatgb/...。
5、动态代理:其用途跟静态代理类型,但可以利用反射机制动态地创建对象,可以减少代理代码的重复,有更好的扩展性。详见:http://blog.csdn.net/lidatgb/...。
6、正向代理:用户可以指定代理服务器转发请求到目标服务器完成,用户知道代理服务器地址和目标服务器地址。常见于FQ代理服务器。
7、反向代理: 用户访问的目标服务器其实是代理服务器,代理服务器做负载均衡后把请求转发到真正的目标服务器执行。常见于负载均衡服务器。
使用场景
由代理的概述中知道,但需要控制对资源或者对象的访问时使用代理模式。从代理的种类中可以进一步看清代理模式的使用场景,无非就是转发远程请求、作为创建开销大对象的替身、在本地保存网络资源、控制一些受保护资源的权限访问、作负载均衡。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。