大家好,我是方圆,小小的代理模式


一、 到底啥是代理模式?

官方的话说,代理模式就是为目标对象提供另外一种访问方式,通过访问代理对象来间接访问目标对象。

我们来打个比方,简单点儿描述,比如我是房东,我要出租房屋,以前呢我直接租给住户,这样就是没有代理。但是现在我觉得我直接找客户出租房屋很麻烦,所以我就把房子交给中介,让中介帮我出租房子,我只管提供房子,中介帮我做带客户看房啊、收费等其他事物,这样,房东有了代理,这就是代理模式。

从这也能看出代理模式的一点好处,让房东专注于提供房子,其他事物由代理做,反映到程序中,就是,能让service层专注于提供服务,采用代理模式来实现其他事物,在不改变service层代码的情况下,提供了其他的功能。

二、静态代理模式

我们还是拿租房这个简单的例子来讲解

这是一个接口,房东实现这个接口,来提供租房子的业务
//租房
public interface Rent {void RentHouse();
}
这个是房东类,在程序中就位于service层
//房东
public class Host implements Rent{public void RentHouse() {System.out.println("房东出租房屋给客户");}
}
//我是代理,房屋中介
public class Proxy implements Rent{private Host host;public void setHost(Host host) {this.host = host;}public void RentHouse() {host.RentHouse();}
}
这个就是客户类
//客户,要租房子的人
public class Client {public static void main(String[] args) {//在没有中介的时候,直接找房东租房Host host = new Host();host.RentHouse();}
}

,房东直接租房子给客户。
下面,房东要找代理了。

public class Client {public static void main(String[] args) {//在没有中介的时候,直接找房东租房Host host = new Host();//这里是一个代理Proxy proxy = new Proxy();proxy.setHost(host);//房东把房子交给中介//中介代替房东出租房屋,调用出租房的方法//理论上还是房东出租给客户房屋,只不过这件事情被中介给做了proxy.RentHouse();}
}


我们这里没有用房东直接调用租房的方法,而是中介调用,同样实现了租房的功能,这样就实现了静态代理模式。
我们这里总结一下代理模式的好处

  1. 可以让service层专注于实现自己的业务,也就是房东只专注于提供房子,中介负责向客户出租和一些细枝末节的事情,我们同样可以在中介代码中,添加一下其他方法,并不影响房东的代码
  2. 要对业务就行扩展时,可修改代理的代码进行添加,而不需要修改service层源码

但是缺点也显而易见,静态嘛,不够灵活,代码冗余,一个service就需要一个代理,使代码翻倍。
为了解决这个缺点就出现了动态代理

三、动态代理模式

我们同样还是需要以上的Rent接口,和Host类
但是这次我们需要创建一个动态代理的类,ProxyInvocationHandler

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyInvocationHandler implements InvocationHandler {//这个了实现了 InvocationHandler 接口
//每个代理的实例需要实现这个接口,从而来调用处理程序的实现
//invoke handler:翻译为中文就是调用处理程序//我们需要实现租房子的这个接口,所以定义一个变量private Rent rent;public void setRent(Rent rent) {this.rent = rent;}//生成代理类的方法public Object getProxy(){//newProxyInstance() 创建代理实例方法// 这个方法中,第一个参数为Invocation类的类加载器//第二个参数,为要让代理实现的类的接口,也就是要实现租房子的接口//第三个参数,是Invocation类本身Object proxyInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);return proxyInstance;}//这个invoke方法,官方介绍中说://每一个代理实例Proxy都由一个关联的调用处理程序invoke,//当在代理实例上调用方法时,方法调用将被编码并分配到其调用处理程序的invoke方法//也就是说,当用代理调用方法的时候,这个invoke方法就会帮代理实现方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//在这里,invoke会帮助Proxy代理实例来实现方法//其中参数 method就是要实现的方法//方法调用invoke(rent,args)来返回结果//其中参数rent是要被实现方法的接口,args默认填写Object result = method.invoke(rent, args);return  result;}
}

下面我们就用客户类来实现一下这个动态代理

public class Client {public static void main(String[] args) {//这里还是有一个房东准备要出租房子Host host = new Host();//创建ProxyInvocationHandler对象,用该对象的方法getProxy()方法创建代理实例//并且该对象实现了InvocationHandler接口,就由了调用处理程序实现的功能,也就是invoke()方法ProxyInvocationHandler handler = new ProxyInvocationHandler();handler.setRent(host); //这里把房东传值给handler中的rent对象,也就是房东把房子交给中介//利用handler对象,调用其中我们写好的getProxy方法,来实例代理,也就是中介Rent proxy = (Rent) handler.getProxy();//这里中介就帮房东出租房子了,也就实现了我们的代理模式proxy.RentHouse();}
}

动态代理解决了静态代理代码冗余的缺点

如果我们将动态代理类中的代码进行修改

将其中这段代码改为private Rent rent;public void setRent(Rent rent) {this.rent = rent;}
如下private Object object;public void setObject(Object object) {this.object = object;}

那么,这样它就成了一个万能的代理,能传入任何类型的接口,那么他就什么都能代理了。

四、 cglib动态代理代码示例

用cglib我们需要导包,如下

        <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.12</version></dependency>

cglib动态代理与JDK动态代理的区别:cglib无需强制实现接口,其生成的代理类是被代理类的子类

我们创建一个需要被代理的类Rent

public class Rent {public void rentHouse(){System.out.println("出租房屋");}
}

随后我们创建cglib动态代理,实现的是MethodInterceptor接口

import java.lang.reflect.Method;public class RentCglib implements MethodInterceptor {//被代理的对象private Object service;//注入被代理的对象public void setService(Object service) {this.service = service;}public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//可以在这里写上增加的功能System.out.println("代理带房客看房");return method.invoke(service, objects);}
}

最后我们写一个测试类,进行测试

import net.sf.cglib.proxy.Enhancer;public class Test {public static void main(String[] args) {//创建租房服务Rent rent = new Rent();//注入租房的类RentCglib rentCglib = new RentCglib();rentCglib.setService(rent);//创建增强器,用来创建动态代理实例Enhancer enhancer = new Enhancer();//注入动态代理要代理的类enhancer.setSuperclass(rent.getClass());//设置回调enhancer.setCallback(rentCglib);//创建动态代理实例Rent rentService = (Rent) enhancer.create();rentService.rentHouse();}
}

输出结果如下

参考文献

b站狂神说


经过一次修改,可读性比之前好了,但是还需要自己写出来才能掌握

23种设计模式——最好理解的代理模式相关推荐

  1. 23种设计模式学习记录之代理模式

    想说的话: 在大学的时候曾经学过这23种设计模式,但是那时没啥编程经验,糊里糊涂过了一遍,没多久就忘记了,工作之后将精力主要集中在学习新技术上,比如springboot,cloud,docker,vu ...

  2. 23种设计模式(7)-代理模式

    定义: 为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用 角色: 1,  抽象角色:声明真实对象 ...

  3. 23种设计模式通俗理解

    23种设计模式通俗理解 1.根据目的来分 2.根据作用范围来分 3.GoF的23种设计模式的功能 1.FACTORY 工厂方法 2.BUILDER建造者模式 3.FACTORY METHOD抽象工厂 ...

  4. JavaScript 23 种设计模式之 4 抽象工厂模式

    JavaScript 23 种设计模式之 4 抽象工厂模式 概念与特点 结构与实现 应用场景 应用实例 总结 概念与特点 概念: 提供一组相关或相互依赖对象的接口.抽象工厂模式是工厂方法模式的升级版, ...

  5. 23种设计模式之单例模式、工厂模式、原型模式、建造者模式

    系列文章目录 第一章:程序设计原则-单一职责.接口隔离.依赖倒置.里式替换 第二章:程序设计原则-开闭原则.迪米特法则.合成复用原则 文章目录 系列文章目录 一.设计模式简单介绍 1.1.什么是设计模 ...

  6. Unity实现:23种设计模式、《游戏编程模式》

    目录 一.23种设计模式在Unity实现 Creational Patterns 创建型模式(5种) 工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式 Structural Patterns ...

  7. 23种设计模式(十一)外观模式(阁瑞钛伦特软件-九耶实训)

    常说的设计模式是23种设计模式,分为3大类: 创建型模式5种:工厂方法.抽象工厂.单例.建造者.原型 结构型模式7种:适配器.代理.桥接.装饰者.外观.享元.组合 行为型模式11种:模板方法.解释器. ...

  8. 23种设计模式(第二章创建者模式5种)

    第二章创建者模式 单例模式 单例模式有 3 个特点: 单例类只有一个实例对象: 该单例对象必须由单例类自行创建: 单例类对外提供一个访问该单例的全局访问点. 单例模式的实现 单例设计模式分类两种: ​ ...

  9. 23种设计模式 -----Day01:简单工厂模式

    目录 前言 1.设计模式(Design pattern)定义 2.为什么要使用设计模式(使用设计模式的意义) 3.设计原则 a.单一职责原则 b.开放封闭原则 c.里氏代换原则 d.迪米特法则 e.依 ...

  10. 【23种设计模式专题】二 工厂模式

    程序猿学社的GitHub,欢迎Star github技术专题 本文已记录到github 文章目录 前言 小故事 传统方式 简单工厂(第一种) 工厂方法模式(第二种) 抽象工厂模式(第三种) 使用工厂方 ...

最新文章

  1. ajax请求必须打断点才能成功,Jquery等待ajax执行完毕继续执行(断点调试正常,运行异常)...
  2. asp.net cache
  3. 在数据库插入带小数点数据的问题
  4. go语言查询某个值是否在数组中_go语言中的数组
  5. 37 FI配置-财务会计-固定资产-组织结构-复制参考折旧表/折旧范围表
  6. Wise Package Studio介绍
  7. Memcache 安装
  8. JAVA API中文在线帮助文档
  9. php screw.so,php screw加密
  10. 看透说破:客户服务首解率(FCR)的迷思
  11. MongoDB修改器使用
  12. c++ 写一个复数计算器
  13. 3D游戏编程与设计-井字棋
  14. Intellij IDEA优化配置(1)------Darcula主题的选择以及字体和颜色配置(基于Intellij IDEA 2019.1)
  15. python打开excel执行vba代码_“Python替代Excel Vba”系列(终):vba中调用Python
  16. 文献笔记--相关:无线通信、安全加密隐私
  17. python电话号码_Python有效电话号码
  18. android使用精伦身份证读卡器读身份证
  19. 【MySQL 8.0 OCP 1Z0-908认证考试】题库精讲--第三讲mysql8.0安装配置升级(中)
  20. oracle prompt出错,Oracle 用 sqlprompt 修改 sqlplus 提示符

热门文章

  1. 2022-03-25 Python作业1
  2. c语言 qt 写小游戏,Qt实现Flappy Bird游戏
  3. c++/c语言(高质量程序设计指南林锐建议总结)
  4. 批量Batch and 动量Momentum
  5. 高效搭建基于dnsmasq通过webui管理的dns服务器
  6. 7、杂项:蓝牙beacon简述
  7. TensorFlow Serving Introduction
  8. C++写入并追加内容到txt中
  9. 硬盘大于2t linux安装 集群 网络,centos 6在大于2T硬盘上安装系统
  10. flyaway mysql_golang通用连接池,支持GRPC,RPC,TCP