Java代理讲解

代理

代理模式是一种结构型设计模式,它允许我们通过添加一个代理对象来控制对另一个对象的访问。代理对象和实际对象具有相同的接口,使得客户端在不知情的情况下可以使用代理对象进行操作。代理对象在与客户端进行交互时,可以控制对实际对象的访问,以实现一些额外的功能,例如访问计数、延迟加载、权限控制等。

代理分为静态代理和动态代理两种

静态代理

静态代理是指在编译期间就已经确定代理类和被代理类的关系。代理类需要手动编写,并且每个被代理类都需要一个对应的代理类

特点

  • 编译期确定:在编译代码时,代理类的代码就已经确定,之后不会再发生变化。
  • 代码冗余:当有多个被代理类或者被代理类的方法很多时,会产生大量重复的代理代码。
  • 灵活性差:如果被代理类的接口发生变化,代理类也需要相应地修改。

 下边我们举一个例子帮助大家进行了解

使用接口进行静态代理

假设我们有一个叫cai的歌手,他只会进行singing和dance两件事情,但是当它要开演唱会时,他要进行收钱才开始操作,但是收钱这个操作他只会专心执行sing和dance这个操作或者说他不会首先这个操作。这时就需要它的经纪人来帮助他进行收钱操作(代理)

定义cai歌手

public class Cai implements Singer {@Overridepublic void singing() {System.out.println("cai 唱歌");}@Overridepublic int dance() {System.out.println("cai 跳舞");return 0;}
}

定义cai代理

public class Caidaili implements  Singer{private Singer cai = new Cai();@Overridepublic void singing() {System.out.println("先收钱");cai.singing();}@Overridepublic int dance() {System.out.println("先收钱");cai.dance();return 0;}
}

他们都要实现Singer这个接口(代理模式的核心思想是通过代理对象来控制对真实对象的访问,代理对象和真实对象需要对外提供一致的服务。接口定义了一组方法签名,实现同一个接口能保证代理对象和被代理对象具有相同的方法,客户端可以以相同的方式调用它们,从而实现对被代理对象的透明访问。)

public interface Singer {void singing();int dance();
}

最后使用main方法进行调用

public static void main(String[] args) {Singer singer = new Caidaili();singer.singing();singer.dance();}

此时来了一位新的歌手为wu,他同样会singing和dance,在假设其自己的方法和代理都实现时,我们只需要修改主代码中的代理对象即可实现

使用继承方式进行静态代理

同样的使用继承方式我们也可以实现上述操作

public class Singer {public void dance(){System.out.println("cai 跳舞");}public int singing(){System.out.println("cai 唱歌");return 100;}
}

 使用被代理类继承代理类

public class SingerSub extends Singer {@Overridepublic void dance() {System.out.println("收钱");super.dance();}@Overridepublic int singing() {System.out.println("收钱");return super.singing();}
}

 最后进行执行

public class Main {public static void main(String[] args) {Singer singer = new SingerSub();singer.singing();singer.dance();}
}

 

但是因为没有接口的实现,我们每次进行都要使用代理类来承接这个被代理类

结合上边的例子问题也随之出现,因为我们在代理类中实例化了被代理类,每一个被代理类都要一个代理类在其内部进行实例化,每出现一个被代理类都要生成一个新的代理类进行代理,极为不方便。

此时,我们就需要一个拥有强大业务能力的“经纪人”(动态代理),来代理所有的被代理对象,不用我们进行频繁的更换经纪人。

动态代理

从 静态代理 章节中为我们可知,静态代理存在着诸多的问题,最主要的问题是静态代理类需要对被代理类做手动的方法映射。造成这个问题的原因是代理对象是通过硬编码得到的,是在程序编译前就已经存在的,所以顺着这个思路,我们不难得到一个方向,如何代理对象不是通过硬编码提前写好的,而是在程序运行中动态生产的,且生成的代理对象可以对被代理类的方法做自动的映射,那么问题不就解决了吗?是的,这也就是动态代理的大致解决方案。

JDK代理(基于接口实现)

我们同样以上边的cai歌手的例子为例

定义一个Singer的接口

public interface Singer {void dance();int singing();
}

 创建一个cai歌手进行实现它

public class Cai implements Singer {@Overridepublic void dance() {System.out.println("Cai 在跳舞");}@Overridepublic int singing() {System.out.println("Cai 在唱歌");return 0;}
}

最后我们使用JDK代理来进行代理cai类

public static void main(String[] args) {Cai cai  = new Cai();//第一个参数:类加载器//第二个参数:代理类需要实现的接口数组//第三个参数:InvocationHandler接口,其中包含了一个invoke方法,该方法会在每次调用代理对象的方法时被触发Singer o = (Singer) Proxy.newProxyInstance(Cai.class.getClassLoader(), new Class[]{Singer.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if("singing".equals(method.getName())){System.out.println("先收钱");}else if("dance".equals(method.getName())){System.out.println("先收钱");}Object invoke = method.invoke(cai, args);//使用反射,将该方法作用到cai对象上return invoke;}});o.singing();}

 当我们想要修改被代理类,我们只需要修改

减少了,代理类的创建 

cglib代理(基于继承进行实现)

创建一个cai对象

public class Cai {public void dance(){System.out.println("cai 跳舞");}public String singing(){System.out.println("cai 唱歌");return "谢谢";}}

创建代理cai的方法

public class CreateCglibProxy {public static Object getProxy(Object o){Enhancer enhancer = new Enhancer();//生成代理对象enhancer.setSuperclass(o.getClass());//将代理对象设置为被代理对象的子类enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object proxyObject, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {if("singing".equals(method.getName())){System.out.println("先收钱");}else if("dance".equals(method.getName())){System.out.println("先收钱");}Object invoke = methodProxy.invokeSuper(proxyObject, args);return invoke;}});return enhancer.create();}
}

最后进行执行

public class Main {public static void main(String[] args) {Cai cai = new Cai();Cai proxy = (Cai) CreateCglibProxy.getProxy(cai);proxy.dance();}
}

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

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

相关文章

利用deepseek快速生成甘特图

一、什么是甘特图 甘特图(Gantt Chart)是一种直观的项目管理工具,广泛应用于多个领域,主要用于​​时间规划、任务分配和进度跟踪​​。 直观性​​:时间轴清晰展示任务重叠或延迟。 ​​灵活性​​:支持…

从零开始学习SLAM|技术路线

概念 视觉SLAM(Simultaneous Localization and Mapping)系统中,整个过程通常分为 前端 和 后端 两个主要部分。前端处理的是从传感器数据(如相机图像、激光雷达等)中提取和处理信息,用于实时定位和建图&am…

LeetCode 解题思路 44(Hot 100)

解题思路: dp 数组的含义: 以 nums[i] 为结尾的最长递增子序列的长度。递推公式: dp[i] Math.max(dp[i], dp[j] 1)。dp 数组初始化: dp[i] 1。遍历顺序: 从小到大去遍历,从 i 1 开始,直到 …

精益数据分析(22/126):解锁创业增长密码与长漏斗分析

精益数据分析(22/126):解锁创业增长密码与长漏斗分析 在创业与数据分析的探索旅程中,我们都在不断寻求新的知识和方法,以提升创业的成功率。我一直期望能和大家共同学习、共同进步,今天就让我们继续深入研…

大模型应用开发之LLM入门

一、大模型概述 1、大模型概念 LLM是指用有大量参数的大型预训练语言模型,在解决各种自然语言处理任务方面表现出强大的能力,甚至可以展现出一些小规模语言模型所不具备的特殊能力 2、语言模型language model 语言建模旨在对词序列的生成概率进行建模…

Vue 计算属性 VS 侦听器:从原理到性能的深度对比

在 Vue 开发中,computed(计算属性)和watch(侦听器)是响应式系统的两大核心工具。 它们看似都能处理数据变化,实则设计理念和应用场景大相径庭。 一、核心区别:数据驱动的两种范式 1. 触发机制…

特斯拉宣布启动自动驾驶网约车测试,无人出租车服务进入最后准备阶段

特斯拉公司于4月24日正式宣布,已在美国得克萨斯州奥斯汀和加利福尼亚州旧金山湾区启动自动驾驶网约车服务的员工内部测试。这项测试将为今年夏季计划推出的完全无人驾驶出租车服务进行最后的验证和准备。 此次测试使用约200辆经过特殊改装的Model 3车型,…

基于springboot的在线教育系统

一、系统架构 前端:vue | element-ui | html | jquery | css | ajax 后端:springboot | mybatis 环境:jdk1.8 | mysql | maven | nodejs | idea 二、代码及数据 三、功能介绍 01. web端-首页1 02. web端-首页2 03. w…

文档编辑:reStructuredText全面使用指南 — 第四部分 高级主题

文档编辑:reStructuredText全面使用指南 — 第四部分 高级主题 reStructuredText(简称RST或ReST)是一种轻量级的标记语言,用于编写结构化的文档。它由Python社区开发,并广泛应用于技术文档、书籍、博客文章等。reStruc…

git Http改用户下载

用原先别人账号,无权下更新 http方式设置自己账号 例如 git fetch --all 提示没有权限从 http://192.168.1.2/gitlab/项目路径.git下载 git remote set-url origin http://your-username192.168.1.2/gitlab/项目路径.git your-username修改成自己的git账号 需要输入一个Tok…

Cancer Cell|scRNA-seq + scTCR + 空间多组学整合分析,揭示CD8⁺ T细胞在免疫治疗中的“双路径” | 临床问题的组学解答

Cancer Cell|scRNA-seq scTCR 空间多组学整合分析,揭示CD8⁺ T细胞在免疫治疗中的“双路径” 👋 欢迎关注我的生信学习专栏~ 如果觉得文章有帮助,别忘了点赞、关注、评论,一起学习 近日,《Cancer Cell》…

Python编程的真谛:超越语法,理解编程本质

你是否也曾陷入这样的误区:学了无数的 Python 语法、刷了几十套题,写起代码却仍然卡顿、举步维艰?这时候你才发现,真正阻碍进步的,从不是语法,而是你对“编程本质”的理解。 如果你只是死记硬背Python的语…

Go协程的调用与原理

Goroutine Go不需要像C或者Java那样手动管理线程,Go语言的goroutine机制自动帮你管理线程。 使用goroutine、 Go语言中使用goroutine非常简单,只需要在调用函数的时候在前面加上go关键字,就可以为一个函数创建一个goroutine。 一个gorout…

自然语言处理(9)—— 共现词矩阵及Python实现

共现词矩阵 1. 概述2. 构建步骤3. 代码实现(Python)结语 共现词矩阵(Co-occurrence Matrix)是自然语言处理(NLP)中用于捕捉词语间语义关系的重要工具。共现矩阵通过统计词语在特定上下文窗口内的共现频率&a…

Spark SQL核心解析:大数据时代的结构化处理利器

在大数据处理领域,Spark以其强大的分布式计算能力脱颖而出,而Spark SQL作为Spark生态系统的重要组成部分,为结构化和半结构化数据处理提供了高效便捷的解决方案。它不仅整合了传统SQL的强大查询功能,还深度集成到Spark的计算框架中…

多态以及多态底层的实现原理

本章目标 1.多态的概念 2.多态的定义实现 3.虚函数 4.多态的原理 1.多态的概念 多态作为面对三大特性之一,它所指代的和它的名字一样,多种形态.但是这个多种形态更多的指代是函数的多种形态. 多态分为静态多态和动态多态. 静态多态在前面已经学习过了,就是函数重载以及模板,…

linux下开发NFC读写器

linux下使用NFC读卡器,基于QT5开发 创建工程,引入lib开始编写代码 创建工程,引入lib 创建一个QT工程,如果是控制台程序,则去掉gui QT - gui引入lib库 LIBS -L$$PWD/lib -lyw60x这里需要将libyw60x.so库文件放在工程…

Linux基础使用-笔记

1. 文件和目录操作 查看当前目录:pwd 命令用于显示当前工作目录的完整路径。 pwd切换目录:cd 命令用于切换工作目录。 # 切换到指定目录 cd /home/user/Documents # 切换到上一级目录 cd .. # 切换到用户主目录 cd ~列出目录内容:ls 命令用…

DAG(有向无环图)计算模型面试内容整理-拓扑排序(Topological Sort)和节点依赖与并行度

拓扑排序(Topological Sort) 拓扑排序(Topological Sort): 拓扑排序是针对有向无环图(DAG)的一种线性排序方法。这种排序方法的特点是,对于DAG中的每一条有向边 (A → B),在拓扑排序中节点A总是排在节点B之前。

23种设计模式-结构型模式之享元模式(Java版本)

Java 享元模式(Flyweight Pattern)详解 🦋 什么是享元模式? 享元模式是一种结构型模式,它通过共享相同的对象来减少内存消耗,适用于大量细粒度对象的场景。关键思想是缓存重复出现的对象,避免…