定义
代理模式的本质是一个中间件,主要目的是解耦合服务提供者和使用者。使用者通过代理间接的访问服务提供者,便于后者的封装和控制。是一种结构性模式。
优缺点
# 优点
低耦合
易扩展
灵活度高
# 缺点
间接访问可能会延迟请求相应
增加工作量
分类
# 静态代理
# 动态代理
代理类本身的实现可能并不简单,加上每一个需要代理的对象均需要实现一个代理类,其工作量本身比较大,易出错。
所谓动态代理(DynamicProxy)是指在程序运行时动态的生成对目标对象的访问接口。
主要用途
1、远程代理
2、虚代理
3、保护代理
4、智能指引代理
5、写时复制(Copy-on-Write)代理
6、缓存代理
7、防火墙代理
8、同步化代理
原理
# Subject
定义RealSubject对外的接口,且这些接口必须被Proxy实现,这样外部调用proxy的接口最终都被转化为对realsubject的调用。
# RealSubject:
真正的目标对象。
# Proxy:
目标对象的代理,负责控制和管理目标对象,并间接地传递外部对目标对象的访问。
1、Remote Proxy: 对本地的请求以及参数进行序列化,向远程对象发送请求,并对响应结果进行反序列化,将最终结果反馈给调用者;
2、Virtual Proxy: 当目标对象的创建开销比较大的时候,可以使用延迟或者异步的方式创建目标对象;
3、Protection Proxy: 细化对目标对象访问权限的控制;
网络代理
// 定义公共接口类Server
public interface Server{
void visit(String url);
}
// 代理服务器ProxyServer
public class ProxyServer implements Server{
private RealServer realServer;
public ProxyServer(String serverName){
this.realServer = new RealServer(serverName);
}
@Override
public void visit(String url){
realServer.visit(url);
}
}
// 目标服务器RealServer
public class RealServer implements Server{
private String serverName;
public RealServer(String serverName){
this.serverName = serverName;
System.out.println("This is " + serverName);
}
@Override
public void visit(String url){
response(url);
}
private void response(String res){
System.out.println("This is response of " + res + " from server:" + serverName);
}
}
// 演示
public class Demo{
public static void main(String[] args){
Server server = new ProxyServer("www.google.com");
server.visit("map.google.com");
}
}
静态代理
静态代理的的代理类是我们自己定义好的,在程序运行之前就已经编译完成。
举例:一个班的学生需要交作业,现在让班长代理交作业,那么班长就是代理,学生就是被代理的对象。
// 这个接口是被代理(学生),和代理(班长)的公共接口
public interface Person{
//交作业
void giveTask();
}
// 学生实现交作业
public class Student implements Person{
private String name;
public Student(String name){
this.name = name;
}
public void giveTask(){
System.out.println(name + "交语文作业");
}
}
// 学生代理类(班长),也实现了Person接口,保存一个学生实体,这样就可以代理学生产生行为。
public class StudentsProxy implements Person{
// 被代理的学生
private Student student;
// 只代理学生对象
public StudentsProxy(Person student){
if(student.getClass() == Student.class) {
this.student = (Student)student;
}
}
// 代理交作业,调用被代理学生的交作业的行为
public void giveTask(){
student.giveTask();
}
}
public class StaticProxyTest{
public static void main(String[] args) {
// 被代理的学生林浅,他的作业上交有代理对象monitor完成
Person linqian = new Student("林浅");
// 生成代理对象,并将林浅传给代理对象
Person monitor = new StudentsProxy(linqian);
// 班长代理交作业
monitor.giveTask();
}
}
动态代理
动态代理的代理类是在程序运行时创建的。
// 这个接口是被代理(学生),和代理(班长)的公共接口
public interface Person{
//交作业
void giveTask();
}
// 学生实现交作业
public class Student implements Person{
private String name;
public Student(String name) {
this.name = name;
}
public void giveTask() {
System.out.println(name + "交语文作业");
}
}
// 实现InvocationHandler接口,实现类中持有一个被代理对象的实例target。
// InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。
public class StuInvocationHandler<T> implements InvocationHandler{
// invocationHandler持有的被代理对象
public T target;
public StuInvocationHandler(T target){
this.target = target;
}
/**
* proxy:代表动态代理对象
* method:代表正在执行的方法
* objects:代表调用目标方法时传入的实参
*/
public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
System.out.println("代理执行" + method.getName() + "方法!");
return method.invoke(target, objects);
}
}
public class ProxyTest{
public static void main(String[] args) {
// 创建一个实例对象,这个对象是被代理的对象
Person linqian = new Student("林浅");
// 创建一个与代理对象相关联的InvocationHandler
InvocationHandler stuHandler = new StuInvocationHandler<Person>(linqian);
// 创建一个代理对象stuProxy来代理linqian,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);
// 代理执行交作业的方法
stuProxy.giveTask();
}
}