Java设计模式——代理模式

静态代理:

Java静态代理是设计模式中的一种,它通过创建一个代理类来代替原始类,从而提供额外的功能或控制原始类的访问。

如何使用Java静态代理

要创建一个静态代理,你需要有一个接口,一个实现该接口的目标类,以及一个代理类,该代理类也实现了该接口。代理类持有一个对目标对象的引用,并在其方法调用中调用目标对象的相应方法。

// 定义一个接口
interface Calculator {int add(int a, int b);
}// 目标类
class CalculatorImpl implements Calculator {@Overridepublic int add(int a, int b) {return a + b;}
}// 代理类
class CalculatorProxy implements Calculator {private Calculator calculator;public CalculatorProxy(Calculator calculator) {this.calculator = calculator;}@Overridepublic int add(int a, int b) {System.out.println("Before calculation");int result = calculator.add(a, b);System.out.println("After calculation");return result;}
}// 测试类
public class ProxyExample {public static void main(String[] args) {Calculator target = new CalculatorImpl();Calculator proxy = new CalculatorProxy(target);int result = proxy.add(5, 3);System.out.println("Result: " + result);}
}

在这个例子中,Calculator是一个接口,CalculatorImpl是目标类,CalculatorProxy是代理类。当我们调用代理类的add方法时,它会首先打印"Before calculation",然后调用目标对象的add方法,最后打印"After calculation"。 

为什么使用静态代理

  • 解耦:可以在不修改目标对象的情况下,通过代理对象添加额外的功能或控制访问。

  • 保持干净:代理类可以为目标对象提供一个干净的接口,隐藏了目标对象的实现细节。

  • 权限控制:可以在代理类中添加额外的权限检查,以控制对目标对象的访问。

缺点

  • 代码冗余:每次添加一个新的功能都需要创建一个新的代理类。

  • 静态:因为代理类是静态的,所以不能在运行时改变它们的行为。

总的来说,静态代理是一种简单且直接的方式来实现代理模式,它在很多情况下都是非常有用的,特别是当你需要对目标对象进行额外控制或添加额外功能时

动态代理:

 Java动态代理是Java语言提供的一个强大的特性,它允许你在运行时创建代理类和代理实例。这使得你可以在运行时为一个接口创建一个代理实例,而不需要手动编写实现该接口的类。动态代理通常在需要添加额外逻辑(例如日志记录、事务管理等)到现有代码中而不修改现有代码的情况下使用。

  • 是在内存中生成代理对象的一种技术
  • 无需手写代理类,也不会存在代码编译的过程。运用在内存中生产代理类的技术在JVM的运行区造一个代理对象,只需对需要修改的部分进行编辑。

编写流程:

  1. 准备一个目标类对象
  2. 使用jdk的API动态的生成代理对象
  3. 调用代理对象执行相应的方法

 

如何使用Java动态代理

要使用Java动态代理,你需要先创建一个接口,然后实现一个InvocationHandler接口,最后使用Proxy.newProxyInstance()方法创建代理实例

1.ClassLoader loader:

固定写法,指定目标类对象的类的加载器即可,用于加载目标类及其接口的字节码文件,通常使用目标类的字节码文件调用getClassLoader()方法可得到。

2.Class<?>[] interfaces:

固定写法,指定目标类的所以接口的字节码对象的数组,通常使用目标类的字节码文件调用getinterfaces()方法可得到。

3.InvocationHander h:

这个参数是一个接口,主要关注它里面的一个方法,它会在代理类调用方法时执行,也就是说,在代理类对象中调用的任何方法都会执行invoke()方法。所以在此方法中进行代码的扩展。

invoke()方法中参数的含义:

  1. proxy:就是代理类对象的一个引用也就是Proxy.newProxyInstance()方法的返回值;此引用几乎不会用到。
  2.  method:对应的就是触发invoke执行的方法的Method对象。假如我们调用了Xxx方法,该方法触发了invoke执行,那么method就是Xxx方法对应的反射对象Method。
  3.   args:代理对象调用方法时传入的实际参数

 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public interface Hello {void sayHello();
}public class HelloImpl implements Hello {@Overridepublic void sayHello() {System.out.println("Hello World!");}
}public class DynamicProxyExample {public static void main(String[] args) {Hello hello = new HelloImpl();Hello proxy = (Hello) Proxy.newProxyInstance(hello.getClass().getClassLoader(),hello.getClass().getInterfaces(),new MyInvocationHandler(hello));proxy.sayHello();}
}public class MyInvocationHandler implements InvocationHandler {private Object target;public MyInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method execution.");Object result = method.invoke(target, args);System.out.println("After method execution.");return result;}
}

在上面的例子中,我们首先定义了一个Hello接口和一个实现该接口的HelloImpl类。然后,我们创建了一个MyInvocationHandler类,实现了InvocationHandler接口,该类在方法调用前后打印日志。最后,在DynamicProxyExample类中,我们使用Proxy.newProxyInstance()方法创建了一个代理实例,并传入了一个MyInvocationHandler实例

 

为什么使用动态代理

  • 解耦:你可以将通用逻辑(如日志记录、事务管理等)与特定的业务逻辑分开。

  • 代码复用:可以为多个对象提供相同的额外功能,而无需在每个类中重复相同的代码。

  • 运行时改变行为:你可以在运行时改变对象的行为,而无需修改源代码。

注意事项

  • 接口代理:动态代理只能为接口创建代理,不能为类创建代理。

  • 性能开销:动态代理可能会带来一些性能开销,因为它涉及反射调用。

总的来说,Java动态代理是一个非常强大的特性,可以在很多场景中帮助你更加灵活地管理和组织你的

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

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

相关文章

民航电子数据库:[E14024]事务内变更操作次数超过最大许可值10000,可通过系统参数max_trans_modify适当调整限制

目录 一、场景二、异常情况三、原因四、排查五、解决 一、场景 1、对接民航电子数据 2、执行delete语句时报错 二、异常情况 三、原因 通过报错信息就可以看出&#xff0c;是系统参数max_trans_modify配置导致 当删除的数据量 > max_trans_modify时&#xff0c;删除就会…

HarmonyOS开发实例:【分布式手写板】

介绍 本篇Codelab使用设备管理及分布式键值数据库能力&#xff0c;实现多设备之间手写板应用拉起及同步书写内容的功能。操作流程&#xff1a; 设备连接同一无线网络&#xff0c;安装分布式手写板应用。进入应用&#xff0c;点击允许使用多设备协同&#xff0c;点击主页上查询…

JVM之方法区的详细解析

方法区 方法区&#xff1a;是各个线程共享的内存区域&#xff0c;用于存储已被虚拟机加载的类信息、常量、即时编译器编译后的代码等数据&#xff0c;虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分&#xff0c;但是也叫 Non-Heap&#xff08;非堆&#xff09; 设置方法…

Latex学习(从入门到入土)3

第一章&#xff1a;排版矩阵 在LaTeX中&#xff0c;排版矩阵可以使用amsmath宏包提供的几种不同环境来实现。以下是一些常用的环境和它们的使用方式&#xff1a; ### 使用matrix环境 matrix环境是最基础的矩阵环境&#xff0c;它创建一个带有边框的矩阵&#xff0c;元素默认…

精益思维驱动人工智能革新:理论到实践的跃迁之旅

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已成为引领未来的关键力量。在这个变革的时代&#xff0c;如何将精益思维与人工智能相结合&#xff0c;推动AI从理论走向实践&#xff0c;成为行业内外关注的焦点。本文&#xff0c;天行健精益生产顾问将分享…

Macbook M1 Pro使用brew安装Docker并安装Nacos【超详细图解】

目录 一、安装 Docker 二、修改 Docker 镜像地址 三、拉取镜像-举例 Nacos 1.拉取镜像 2.查看本地镜像 3.删除镜像 四、启动容器 1.启动 Nacos 容器&#xff1a; I.方式一【推荐】 II.方式二【懒人推荐】 2.访问 Nacos Web 控制台 3.进入容器和退出容器 五、配置…

麻将的玩法及技巧

麻将是一种古老而受欢迎的博弈游戏&#xff0c;其玩法和技巧多种多样&#xff0c;因地区和玩家习惯的不同而有所差异。以下是一些通用的麻将玩法和技巧&#xff1a; 一、玩法 洗牌与码牌&#xff1a;玩家双手搓动牌&#xff0c;使牌均匀而无序地运动&#xff0c;称为“洗牌”。…

Java处理CSV类库:OpenCSV

一&#xff1a;CSV简介 Comma-Separated Values(CSV), 因分隔符没有严格指定规范标准&#xff0c;可以使用逗号&#xff0c;也可以使用其他字符&#xff08;如制表符\t、分号;等&#xff09;&#xff0c;所以CSV也称为 逗号分隔值或者字符分隔值。csv文件是使用纯文本来存储表…

MSSQL 命令行操作说明 sql server 2022 命令行下进行配置管理

说明&#xff1a;本文的内容是因为我在导入Access2019的 *.accdb 格式的数据时&#xff0c;总是出错的背景下&#xff0c;不得已搜索和整理了一下&#xff0c;如何用命令行进行sql server 数据库和用户管理的方法&#xff0c;作为从Access2019 直接导出数据到sql server 数据库…

linux限权

shell命令以及运行原理 什么是shell命令&#xff1a; 将使用者的命令翻译给核心&#xff08;kernel&#xff09;处理。同时&#xff0c;将核心的处理结果翻译给使用者。 shell就相当于操作系统外的一层外壳 其实就是登录linux时的一个可执行程序&#xff08;进程&#xff09…

安装kali虚拟机

第一步&#xff1a;安装vmware 安装到最后&#xff0c;会提示输入序列号 安装成功后的图标 第二步&#xff1a;创建一个虚拟主机 创建了一个虚拟机 第三步&#xff1a;给虚拟机安装系统 安装系统&#xff0c;都必须有 系统镜像文件 一般系统镜像文件的后缀是 .iso 第一步&a…

利用CNN-Bigru-Attention模型输电线路故障诊断(Python代码,TensorFlow框架,)

效果视频&#xff1a;利用CNN-Bigru-Attention模型输电线路故障诊断(Python代码&#xff0c;TensorFlow框架&#xff0c;压缩包带有数据集和代码&#xff0c;解压缩可直接运行)_哔哩哔哩_bilibili 售后包免费远程协助运行&#xff08;用向日葵或者todesk软件协助&#xff09; …

GoogleNet网络训练集和测试集搭建

测试集和训练集都是在之前搭建好的基础上进行修改的&#xff0c;重点记录与之前不同的代码。 还是使用的花分类的数据集进行训练和测试的。 一、训练集 1、搭建网络 设置参数&#xff1a;使用辅助分类器&#xff0c;采用权重初始化 net GoogleNet(num_classes5, aux_logi…

Midjourney常见玩法及prompt关键词技巧

今天系统给大家讲讲Midjourney的常见玩法和prompt关键词的一些注意事项&#xff0c;带大家入门&#xff5e;&#xff08;多图预警&#xff0c;建议收藏&#xff5e;&#xff09; 一、入门及常见玩法 1、注册并添加服务器&#xff08;会的童鞋可跳过&#xff5e;&#xff09; …

实在智能携AI Agent智能体亮相2024年度QCon全球软件开发大会

4月11日-13日&#xff0c;以“全面进化”作为2024年度主题的「QCon全球软件开发大会暨智能软件开发生态展」在北京隆重举行。作为AI准独角兽和超自动化头部企业&#xff0c;实在智能应邀出席发表《面向办公自动化领域的AI Agent建设思考与分享》演讲及圆桌交流&#xff0c;展示…

反转二叉树(力扣226)

解题思路&#xff1a;用队列进行前序遍历的同时把节点的左节点和右节点交换 具体代码如下&#xff1a; class Solution { public:TreeNode* invertTree(TreeNode* root) {if (root NULL) return root;swap(root->left, root->right); // 中invertTree(root->left)…

OpenHarmony南向开发案例【智慧中控面板(基于 Bearpi-Micro)】

1 开发环境搭建 【从0开始搭建开发环境】【快速搭建开发环境】 参考鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或复制转到。 【注意】&#xff1a;快速上手教程第六步出拉取代码时需要修改代码仓库地址 在MobaXterm中输入…

【模拟】Leetcode 提莫攻击

题目讲解 495. 提莫攻击 算法讲解 前后的两个数字之间的关系要么是相减之差 > 中毒时间 &#xff0c;要么反之 那即可通过示例&#xff0c;进行算法的模拟&#xff0c;得出上图的计算公式 class Solution { public:int findPoisonedDuration(vector<int>& time…

至少需要[XXXXMB]内存才能安装(宝塔导入数据库提示)

①我的2g内存腾讯云服务器想安装mysql8.0 ②宝塔提示“至少需要[3700MB]内存才能安装” 将数据库部署到宝塔上的时候提示-----》至少需要[XXXXMB]内存才能安装&#xff0c;解决的方法其实也很简单。 首先&#xff0c;进入文件夹/www/server/panel/class&#xff0c;找到找到…

PostgreSQL的学习心得和知识总结(一百三十八)|深入理解PostgreSQL数据库之Protocol message构造和解析逻辑

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…