Java的三种代理模式实现

代理模式的定义:

Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问。)

简单说,就是设置一个中间代理来控制访问原目标对象,达到增强原对象的功能和简化访问方式的目的。

图片

代理模式通用类图

Java实现代理模式分为两类三种,两类是静态代理动态代理,动态代理又可以分为JDK动态代理CGLIB动态代理

图片

Java实现代理模式

静态代理

静态代理比较简单,代理类需要实现和目标接口类一样的接口。

图片

Solver静态代理类图

  • 接口类:ISolver

    public interface ISolver {void solve();
    }
    
  • 目标类:Solver

    public class Solver implements ISolver {@Overridepublic void solve() {System.out.println("疯狂掉头发解决问题……");}
    }
    
  • 代理类:SolverProxy,代理类也要实现接口,并且还要维护一个目标对象。

    public class SolverProxy implements ISolver {//目标对象private ISolver target;public SolverProxy(ISolver target) {this.target = target;}@Overridepublic void solve() {System.out.println("请问有什么能帮到您?");target.solve();System.out.println("问题已经解决啦!");}
    }
    
  • 客户端;Client

    public class Client {public static void main(String[] args) {//目标对象:程序员ISolver developer = new Solver();//代理:客服小姐姐SolverProxy csProxy = new SolverProxy(developer);//目标方法:解决问题csProxy.solve();}
    }
    
  • 运行结果

    请问有什么能帮到您?
    疯狂掉头发解决问题……
    问题已经解决啦!
    

我们看到,通过静态代理,可以在不修改目标对象的前提下扩展目标对象的功能。

但是,它也有一些问题:

  • 冗余:由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。

  • 维护性不佳:一旦接口增加方法,目标对象与代理对象都要进行修改。

JDK动态代理

JDK动态代理利用了JDK反射机制,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。

它主要用到了两个反射类的API:

  • java.lang.reflect Proxy| static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h):返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序

  • java.lang.reflect InvocationHandler|Object invoke(Object proxy, Method method, Object[] args) :在代理实例上调用目标方法,并返回结果。

我们来看看使用JDK动态代理之后的客服代理场景。

图片

JDK动态代理类图

  • 接口类:ISolver

    public interface ISolver {void solve();
    }
    
  • 目标类:Solver,目标类需要实现接口类。

    public class Solver implements ISolver {@Overridepublic void solve() {System.out.println("疯狂掉头发解决问题……");}
    }
    
  • 动态代理工厂:ProxyFactory,这里的动态代理工厂,不需要实现接口,直接采用反射的方式生成一个目标对象的代理对象实例。

    ps:这里用了一个匿名内部类的方法,还有一种方法,动态代理类实现InvocationHandler接口,大体上类似,就不再给出例子了。

    public class ProxyFactory {// 维护一个目标对象private Object target;public ProxyFactory(Object target) {this.target = target;}// 为目标对象生成代理对象public Object getProxyInstance() {return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("请问有什么可以帮到您?");// 调用目标对象方法Object returnValue = method.invoke(target, args);System.out.println("问题已经解决啦!");return null;}});}
    }
  • 客户端:Client

    客户端生成一个代理对象实例,通过代理对象调用目标对象方法的时候,就会进入invoke()方法,最后是通过反射的方式调用目标对象的方法。

    public class Client {public static void main(String[] args) {//目标对象:程序员ISolver developer = new Solver();//代理:客服小姐姐ISolver csProxy = (ISolver) new ProxyFactory(developer).getProxyInstance();//目标方法:解决问题csProxy.solve();}
    }
    
  • 运行结果:

    请问有什么可以帮到您?
    疯狂掉头发解决问题……
    问题已经解决啦!
    

我们简单总结一下静态代理和动态代理的主要区别:

图片

静态代理动态代理最主要区别

  • 静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件

  • 动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中

我们也观察到,JDK动态代理,目标对象必须得实现接口,也就是说它是面向接口的,假如我们不想要接口怎么办呢?

Cglib动态代理

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成,它是通过继承来实现的。

我们来看看使用Cglib之后,我们的客服代理是什么样的:

图片

Cglib动态代理类图

  • 引入依赖:Cglib是第三方类库,需要引入依赖

            <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.5</version></dependency>
    
  • 目标类:Solver,这里目标类不用再实现接口。

    public class Solver {public void solve() {System.out.println("疯狂掉头发解决问题……");}
    }
    
  • 动态代理工厂:

    public class ProxyFactory implements MethodInterceptor {//维护一个目标对象private Object target;public ProxyFactory(Object target) {this.target = target;}//为目标对象生成代理对象public Object getProxyInstance() {//工具类Enhancer en = new Enhancer();//设置父类en.setSuperclass(target.getClass());//设置回调函数en.setCallback(this);//创建子类对象代理return en.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("请问有什么可以帮到您?");// 执行目标对象的方法Object returnValue = method.invoke(target, args);System.out.println("问题已经解决啦!");return null;}}
    
  • 客户端:Client

    public class Client {public static void main(String[] args) {//目标对象:程序员Solver developer = new Solver();//代理:客服小姐姐Solver csProxy = (Solver) new ProxyFactory(developer).getProxyInstance();//目标方法:解决问题csProxy.solve();}
    }
    
  • 运行结果

    请问有什么可以帮到您?
    疯狂掉头发解决问题……
    问题已经解决啦!
    

我们可以看到Cglib动态代理和JDK动态代理最大的区别就是:

  • 使用JDK动态代理的对象必须实现一个或多个接口

  • 使用Cglib动态代理的对象则无需实现接口,达到代理类无侵入。

我们还需要注意:

  • CGLib不能对声明为final的方法进行代理,因为是通过继承父类的方式实现,如果父类是final的,那么就无法继承父类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/212372.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ProEasy机器人案例:电池边包胶

如下图所示&#xff0c;对一个电池三边包边&#xff0c;因客户现场有很多规格电池的大小&#xff0c;所以就需要建立动态的工具坐标来实现适配所有种类的电池 程序如下&#xff1a;Ddome程序 function Speed(num) --速度设置 MaxSpdL(2000) --movl最大速度…

茄子科技张韶全:跨多云大数据平台DataCake在OceanBase的实践

11 月 16 日&#xff0c;OceanBase 在北京顺利举办 2023 年度发布会&#xff0c;正式宣布&#xff1a;将持续践行“一体化”产品战略&#xff0c;为关键业务负载打造一体化数据库。其中&#xff0c;在“数字化转型升级实践专场”&#xff0c;我们有幸邀请到了茄子科技大数据技术…

数据库:JDBC编程

专栏目录 MySQL基本操作-CSDN博客 MySQL基本操作-CSDN博客 数据库的增删查改&#xff08;CRUD&#xff09;基础版-CSDN博客 数据库增删改查&#xff08;CRUD&#xff09;进阶版-CSDN博客 数据库的索引-CSDN博客 基本概念 JDBC编程就是通过Java代码来操作数据库 api 数据库是…

Apache+mod_jk模块代理Tomcat容器

一、背景介绍 最近在看Tomcat运行架构原理, 正好遇到了AJP协议(Apache JServ Protocol). 顺道来研究下这个AJP协议和具体使用方法. 百度百科是这么描述AJP协议的: AJP&#xff08;Apache JServ Protocol&#xff09;是定向包协议。因为性能原因&#xff0c;使用二进制格式来传输…

postcss-pxtorem实现页面自适应的原理

先声明一点这玩意本身不能实现哈&#xff0c;他只是一个工具&#xff0c;更是一个postcss的插件 帮助我们从px转化成为rem比如我们的代码 div {height: 100px;width: 100px; }经过这个插件转化之后变成 假设变成下面这样哈 div {height: 1rem;width: 1rem; }其他没啥子太大作…

2023年江西省“振兴杯”网络信息行业职业技能竞赛 Web4 Writeup

这次振兴杯碰到的一道题&#xff0c;某些姿势之前貌似没有碰过&#xff0c;简单记一下吧 源码 <?php class Bird{public $funcs;public $salt;public $flag;function say_flag(){$secret hash_hmac(sha256, $_GET[salt], file_get_contents(/flag));$hmac hash_hmac(sha…

企业软件的分类有哪些|app小程序定制开发

企业软件的分类有哪些|app小程序定制开发 企业软件是指为了满足企业运营和管理需求而开发的软件系统。根据不同的功能和应用领域&#xff0c;企业软件可以分为以下几个分类&#xff1a; 1. 企业资源计划&#xff08;Enterprise Resource Planning&#xff0c;ERP&#xff09;软…

【UE5】瞬移+马赛克过渡效果

效果 步骤 1. 新建一个工程&#xff0c;创建一个Basic关卡 2. 添加第三人称游戏资源到内容浏览器 3. 新建一个材质&#xff0c;这里命名为“M_Pixel” 打开“M_Pixel”&#xff0c;设置材质域为“后期处理” 在材质图表中添加如下节点 此时效果如下&#xff0c;已经有马赛克的…

Electron+Ts+Vue+Vite桌面应用系列:TypeScript常用语法详解

文章目录 1️⃣ TypeScript常用讲解1.1 使用1.2 字符串1.3 数字1.3 布尔1.4 数组1.5 元组1.6 枚举1.7 any1.8 void1.9 object1.10 函数指定返回值的类型1.11 联合类型1.12 类型断言1.13 接口1.14 函数类型1.15 类类型1.16 泛型 2️⃣ 类2.1 类的基本写法2.2 类的继承2.3 类的修…

【算法集训】基础数据结构:三、链表

链表就是将所有数据都用一个链子串起来&#xff0c;其中链表也有多种形式&#xff0c;包含单向链表、双向链表等&#xff1b; 现在毕竟还是基础阶段&#xff0c;就先学习单链表吧&#xff1b; 链表用头结点head表示一整个链表&#xff0c;每个链表的节点包含当前节点的值val和下…

【Python源码保护】02 - pyc

1. python编译过程 Python虽然是一门解释型语言&#xff0c;但Python程序执行时&#xff0c;也需要将源码进行编译生成字节码&#xff0c;然后由Python虚拟机进行执行&#xff0c;因此Python解释器实际是由两部分组成&#xff1a;编译器和虚拟机。 Python程序执行过程和Java类…

C语言--不使用库函数,把一个数字转为字符串【详细解释】

一.题目描述 输入一个数字&#xff0c;把他转为字符串 比如&#xff1a;输入数字&#xff1a;12345 输出&#xff1a;12345&#xff08;这里的12345是字符串12345&#xff09; 二.思路分析 比如给定一个数字12345&#xff0c;先把它转为字符54321&#xff08;“54321”&#…

处理器中的TrustZone之安全状态

在这篇博客中&#xff0c;我们将讨论处理器内对TrustZone的支持。其他部分则涵盖了在内存系统中的支持&#xff0c;以及建立在处理器和内存系统支持基础上的软件情况。 3.1 安全状态 在Arm架构中&#xff0c;有两个安全状态&#xff1a;安全状态和非安全状态。这些安全状态映射…

区块链密码学:基础知识、应用与未来发展

一、引言 区块链技术&#xff0c;作为一种分布式、去中心化的数据管理方式&#xff0c;密码学在其安全性和可靠性方面发挥着至关重要的作用。本文将详细介绍区块链密码学的基础知识、应用以及未来发展趋势。 二、区块链密码学基础知识 区块链密码学是区块链技术的核心组成部分…

深入理解 Java 虚拟机(JVM)从入门到精通

目录 一、JVM内存结构1、堆&#xff08;Heap&#xff09;&#xff08;1&#xff09;特点&#xff08;2&#xff09;堆内存分配&#xff08;3&#xff09;晋升到老年代的方式&#xff08;4&#xff09;堆内存检验方式2、虚拟机栈&#xff08;VM Stack&#xff09;&#xff08;1&…

Logstash使用指南

介绍 Logstash是一个开源数据收集引擎&#xff0c;具有实时管道功能。它可以动态地将来自不同数据源的数据统一起来&#xff0c;并将数据标准化到你所选择的目的地。尽管Logstash的早期目标是搜集日志&#xff0c;现在它的功能已完全不只于此。任何事件类型都可以加入分析&…

机械行业解决云存储的企业云盘推荐

随着科技的飞速发展&#xff0c;机械行业在取得显著成果的同时&#xff0c;也面临着一些独特的挑战。本文将深入探讨机械行业所面临的主要问题&#xff0c;并详细介绍Zoho WorkDrive企业云盘所提供的解决方案&#xff0c;以帮助企业应对这些挑战。 一、机械行业面临的主要问题 …

JavaScript添加快捷键、取消浏览器默认的快捷操作、js查看键盘按钮keycode值

document.addEventListener("keydown",function (event) {// 如果不知道按键对应的数字&#xff08;keyCode&#xff09;是多少可以弹出查看一下// alert(event.keyCode)if (event.ctrlKey && event.altKey && event.view["0"] null){if(…

zabbix配置snmp trap--使用snmptrapd和Bash接收器--图文教程

1.前言 我的zabbix的版本是5.0版本&#xff0c;5.0的官方文档没有使用bash接收器的示例&#xff0c;6.0的官方文档有使用bash接收器的示例&#xff0c;但是&#xff0c;下载文件的链接失效&#xff1f;&#xff01; 这里讲解zabbix-server端配置和zabbix web端配置 2.zabbix-…

赛事回顾 | 首届“智航杯“全国无人机智能算法竞赛落幕

11月28日&#xff0c;首届“智航杯”全国无人机智能算法竞赛实物赛在海南省三亚市成功落下帷幕。此次竞赛自2023年4月启动以来&#xff0c;共有来自全国145所高等院校和50多所企事业单位的1253支团队、3655人报名参赛&#xff0c;最终有6支队伍脱颖而出&#xff0c;入围了实物赛…