代理模式(十五)代理商模式
相信自己,请一定要相信自己
上一章简单介绍了享元模式(十四), 如果没有看过, 请观看上一章
一. 代理模式
引用 菜鸟教程里面的代理模式介绍: https://www.runoob.com/design-pattern/proxy-pattern.html
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
一.一 介绍
意图: 为其他对象提供一种代理以控制对这个对象的访问。
主要解决: 在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
何时使用: 想在访问一个类时做一些控制。
如何解决: 增加中间层。
关键代码: 实现与被代理类组合。
应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
使用场景: 按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。
注意事项: 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
二. 代理模式
有 静态代理, 动态代理 (JDK代理) 和 Cglib 代理 ( 可以在内存动态的创建对象)
二.一 静态代理
二.一.一 教师讲课的接口
public interface ITeacher { public void talk(); }二.一.二 一个教师讲课的接口实现
@Slf4j public class RealTeacher implements ITeacher{ @Override public void talk() { log.info("老师正在讲课"); } }二.一.三 不使用代理
@Test public void noProxyTest() { ITeacher iTeacher = new RealTeacher(); iTeacher.talk(); }INFO [main] (RealTeacher.java:16) - 老师正在讲课
二.一.四 使用代理
@Slf4j public class TeacherProxy implements ITeacher{ private ITeacher iTeacher ; public TeacherProxy (ITeacher iTeacher) { this.iTeacher = iTeacher; } @Override public void talk() { log.info("老师提前备课--> 用户 prepare 操作"); iTeacher.talk(); log.info("老师课后总结--> 用户 after 操作"); } }二.一.五 代理测试方法
@Test public void oneTest() { RealTeacher realTeacher = new RealTeacher(); TeacherProxy teacherProxy = new TeacherProxy(realTeacher); teacherProxy.talk(); }二.二 动态代理
二.二.一 接口
public interface ITeacher2 { public void talk(); public void hello (String name); }二.二.二 接口实现
@Slf4j public class RealTeacher2 implements ITeacher2{ @Override public void talk() { log.info("老师正在讲课"); } @Override public void hello(String name) { log.info("你好啊 {}", name); } }二.二.三 JDK 代理实现
@Slf4j public class TeacherProxy2 { private Object target ; public TeacherProxy2 (Object target) { this.target = target; } /** 获取动态代理 */ public Object getProxyInstance() { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { log.info("JDK代理开始"); Object returnVal = method.invoke(target, args); log.info("JDK代理结束"); return returnVal; } } ); } }二.二.四 代理测试
@Test public void twoTest() { ITeacher2 teacher2 = new RealTeacher2(); // 处理转换代理信息 ITeacher2 target = (ITeacher2)(new TeacherProxy2(teacher2).getProxyInstance()); // 进行处理 target.hello("张三"); }二.三 Cglib 代理
二.三.一 一个普通的类
@Slf4j public class RealTeacher3 { public void talk() { log.info("老师正在讲课"); } public void hello(String name) { log.info("你好啊 {}", name); } }二.三.二 对该类进行代理 TeacherProxy3
@Slf4j public class TeacherProxy3 implements MethodInterceptor { private Object target; public TeacherProxy3(Object target) { this.target = target; } public Object getProxyInstance () { // 创建工具类 Enhancer Enhancer enhancer = new Enhancer(); // 设置父类 enhancer.setSuperclass(target.getClass()); // 设置回调函数, 主要是这个。 enhancer.setCallback(this); // 创建子类对象,即代理对象 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { log.info("CGLIB 代理开始"); Object returnVal = methodProxy.invoke(target, objects); log.info("CGLIB 代理结束"); return returnVal; } }二.三.三 代理测试
@Test public void threeTest() { RealTeacher3 realTeacher3 = new RealTeacher3(); // 处理转换代理信息 RealTeacher3 target = (RealTeacher3)new TeacherProxy3(realTeacher3).getProxyInstance(); // 进行处理 target.hello("张三"); }三. Hutool 的 JDK 代理
可以使用 hutool 的 ProxyUtil ProxyFactory 进行代理
@Test public void fourTest() { ITeacher2 teacher2 = new RealTeacher2(); ITeacher2 proxy = ProxyUtil.proxy(teacher2, new SimpleAspect()); proxy.hello("hutool 工具类的代理"); ITeacher2 proxy2 = ProxyFactory.createProxy(teacher2, new Aspect() { @Override public boolean before(Object target, Method method, Object[] args) { log.info(">>>> 代理之前执行的操作"); return true; } @Override public boolean after(Object target, Method method, Object[] args, Object returnVal) { log.info(">>>> 代理之后执行的操作"); return true; } @Override public boolean afterException(Object target, Method method, Object[] args, Throwable e) { log.info(">>>> 异常时执行的操作"); return true; } }); proxy2.hello("hutool 工厂的代理"); }CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。
所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。
同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理
本章节的代码放置在 github 上:
https:///yuejianli/DesignPattern/tree/develop/Proxy
谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!
代理模式(静态代理模式、动态代理模式、cgLib代理模式、拦截器)动态代理模式
设计模式之代理模式、动态代理模式、Cglib代理模式动态代理是代理模式吗
代理模式-静态代理模式 代理模式-动态代理(基于接口,JDK动态代理)动态代理是代理模式吗
远翔MCU代理商,远翔单片机代理商,远翔代理商,远翔总代理台湾远翔芯片
【设计模式】代理模式 ( 代理模式结构 | 客户端 | 主题对象 | 被代理对象 | 代理对象 )设计模式的代理模式
【设计模式】代理模式 ( 动态代理使用流程 | 创建目标对象 | 创建被代理对象 | 创建调用处理程序 | 动态创建代理对象 | 动态代理调用 )动态代理是代理模式吗
设计模式之代理模式(包含静态代理和动态代理)设计模式的代理模式