代理模式---静态代理和动态代理

news2024/9/19 12:38:40

代理模式

        代理模式:给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式

        代理模式角色分为 3 种:

Subject(抽象主题角色):定义代理类和真实主题的公共对外方法,通常被设计成接口;

RealSubject(真实主题角色):真正实现业务逻辑的类;

Proxy(代理主题角色):用来代理和封装真实主题;

        代理模式的结构比较简单,其核心是代理类,为了让客户端能够一致性地对待真实对象和代理对象,在代理模式中引入了抽象层。

         如果根据字节码的创建时机来分类,可以分为静态代理动态代理

静态代理

        所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了

        假设有UserService接口及其实现类UserServiceImpl,我们需要在不改变实现类代码的基础上,增加日志记录的功能。

//Subject

public interface UserService {
	public void select();
	public void update();

}

//RealSubject 真实主题对象(真正的业务类)

public class UserServiceImpl implements UserService{	
	public void select() {
		System.out.println("查询selectById");		
	}	
	public void update() {
		System.out.println("更新updateById");
		
	}
}

//Proxy 代理对象

public class UserServiceProxy implements UserService{
	//创建真正的主题对象
    private UserServiceImpl realUserService=new UserServiceImpl ();

    @Override
	public void select() {
        long begin=System.currentTimeMillis();
        realUserService.select();
        long end=System.currentTimeMillis();
		System.out.println("select的执行时间为:"+(end-begin)+"毫秒");

    }
    @Override
	public void update() {
		// TODO Auto-generated method stub
		long begin=System.currentTimeMillis();
		realUserService.update();
		long end=System.currentTimeMillis();
		System.out.println("update的执行时间为:"+(end-begin)+"毫秒");
	}
}

//Test测试类

public class Test {
	public static void main(String[] args) {
        //创建代理对象
        UserServiceProxy proxy=new UserServiceProxy();
        proxy.select();
		proxy.update();
    }
}

//运行结果:

查询selectById
select的执行时间为:0毫秒
更新updateById
update的执行时间为:0毫秒

        通过静态代理,我们可以达成增强功能而不污染原代码,这是静态代理的优点。但是在一些场景复杂的时候,静态代理的缺点也会暴露出来:

1、 当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式

只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大,导致代码可读性差。

新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类,难以管理。

2、 当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护

动态代理

        Java中两种常见的动态代理方式:JDK原生动态代理CGLIB动态代理(第三方开源类库)。

JDK动态代理

        JDK动态代理主要涉及两个类:java.lang.reflect.Proxy 和java.lang.reflect.InvocationHandler。我们通过编写一个调用逻辑处理器 LogHandler 类案例来提供日志增强功能,并实现 InvocationHandler 接口;在 LogHandler 中维护一个目标对象,这个对象是被代理的对象(真实主题角色);在 invoke()方法中编写方法调用的逻辑处理。

//准备好两个真实主题对象及其接口:

//1.UserService和UserServiceImp

public interface UserService {
	public void select();
	public void update();

}
//RealSubject 真实主题对象(真正的业务类)
public class UserServiceImpl implements UserService{	
	public void select() {
		System.out.println("查询selectById");		
	}	
	public void update() {
		System.out.println("更新updateById");
		
	}
}

//2.OrderService 和OrderServiceImp

public interface OrderService {
	public void creat(int money,int uid);

}
public class OrderServiceImpl implements OrderService{
	@Override
	public void creat(int money, int uid) {
		System.out.printf("商品%d的价格是:%d",uid,money);
		System.out.println();
	}

}

//InvocationHandler 接口的实现类

//用于检测方法运行时间的Handler执行器
public class PerformanceInvocationHandler implements InvocationHandler{
    private Object real;
	public PerformanceInvocationHandler(Object real) {
		this.real=real;
	}

    @Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //开始时间
		long begin=System.currentTimeMillis();
		
		//真实业务对象当前的执行方法(基于反射)
        //相当于调用了creat()、select()或update()方法
        //传入的真实主题对象是谁,就调用谁的方法
		Object returnValue=method.invoke(real, args);
		
        //结束时间
		long end=System.currentTimeMillis();
		
		System.out.println("方法耗时:"+(end-begin)+"毫秒");
		
		return returnValue;
	}

}

//实现OrderService代理的测试类

public class Test01 {
	public static void main(String[] args) {
        //真实主题对象
		OrderServiceImpl realOrderService=new OrderServiceImpl();
        //获取类加载器
		ClassLoader classLoader=realOrderService.getClass().getClassLoader();
        //接口列表
		Class[] interfaces=realOrderService.getClass().getInterfaces();
        //创建InvocationHandler对象(动态代理执行逻辑)
		PerformanceInvocationHandler h=new PerformanceInvocationHandler(realOrderService);

        //创建一个代理对象
		OrderService orderServiceProxy=(OrderService)Proxy.newProxyInstance(classLoader, interfaces, h);
        /调用方法
		orderServiceProxy.creat(1234, 1);
	
	}

}

//运行结果:

商品1的价格是:1234
方法耗时:33毫秒

//实现UserService代理的测试类

public class Test02 {
	public static void main(String[] args) {
		//创建真实主题对象
		UserServiceImpl realUserService=new UserServiceImpl();
		
		//获取类加载器
		ClassLoader loader=realUserService.getClass().getClassLoader();
		
		//获取接口列表
		Class[] interfaces=realUserService.getClass().getInterfaces();
		
		//Handler
		PerformanceInvocationHandler h=new PerformanceInvocationHandler(realUserService);
		
		//创建动态代理对象
		UserService userServiceProxy=(UserService)Proxy.newProxyInstance(loader, interfaces, h);
		
		//调用方法
		userServiceProxy.update();
	}

}

 //运行结果:

更新updateById
方法耗时:0毫秒

        通过动态代理,我们不再需要创建不同代理类来实现不同的逻辑方法。动态代理是通过Proxy创建代理对象,然后将接口方法“代理”给InvocationHandler完成的。

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

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

相关文章

【JavaScript】算法之排序搜索

排序 冒泡排序 选择排序 插入排序 从第一个元素开始,该元素可以被认为已经被排序取出下一个元素,在已经排序好的序列中,从后往前扫描直到找到小于或者等于该元素的位置将该位置后面的所有已经排序的元素从后往前移动将该元素插入到该位置重复…

鲲鹏云-docker安装mysql8.0-并设置参数(--lower-case-table-names=1)

前言: 由于鲲鹏云是arm架构,公司现有的镜像就用不了,为了搭建个测试环境,记录一下搭建过程 注意在mysql8.0里面lower-case-table-names必须在第一次安装时设置。 ①镜像的获取 鲲鹏镜像pull下来是不能跑的,会提示内…

自我评估与改进:TMS优化自检清单

自我评估与改进:TMS优化自检清单 在当今快速变化的物流行业中,运输管理系统(TMS)的优化成为企业提升运营效率、降低成本、增强竞争力的关键。为了帮助企业和物流管理者全面评估TMS的运行状况,识别并优化潜在问题&…

优思学院|中国六西格玛研究调查2025

四年前,优思学院与精益六西格玛专业协会(LSSPA)共同发起了一项具有里程碑意义的调查研究——《中国六西格玛调查研究 2020》。这是中国第一次全面了解六西格玛在本地企业中的发展现状、应用情况以及所面临的挑战和机遇的调研项目。这个调查不…

Matlab进阶绘图第68期—带分组折线段的分区柱状图

上一篇文章分享了分区柱状图的绘制方法: 带分组折线段的分区柱状图是在原始分区柱状图的基础上,再添加分组折线段,用以增加一个对象的表达。 由于Matlab中未收录的带分组折线段的分区柱状图的绘制方法,因此需要大家自行解决。 本…

NEMESIS: NORMALIZING THE SOFT-PROMPT VECTORS OF VISION-LANGUAGE MODELS

文章汇总 发现的现象 动机的描述 Norm增加会导致性能下降,Norm降低会导致性能上升。于是作者提出: 我们需要规范化VLMs中的软提示吗? 实验验证 在左图中的紫色块中可以看到,随着模型性能的上升,Norm value会不断下降。 解决…

RedisTemplate混用带来的序列化问题

最近在工作中发现一个现象,项目中使用了不同的 RedisTemplate 来操作redis,有的同事用默认的 RedisTemplate ,有的同事用 StringRedisTemplate。这就导致了我本次遇到的问题: 在一次需求中,我需要从 redis 中取值&…

AIGC产品经理自学不迷路!全网最全AI产品大模型的学习教程!

一、《AI产品经理知识扫盲》 1️⃣【AI的产品形态到底是什么】? 没有固定形态。实际上AI只是一种对传统产品或服务赋能的手段而已,将各种“中间件”(通常是一种训练好的模型,当输入一定数据后自动返回一定的输出值)、…

【WRF工具】WRF Domain Wizard第一期:软件下载及安装

【WRF工具介绍】WRF Domain Wizard下载及安装 1 WRF Domain Wizard 的主要功能2 使用 WRF Domain Wizard 的步骤2.1 安装 WRF Domain Wizard:2.2 启动 WRF Domain Wizard:2.3 定义计算域:2.4 生成配置文件:2.5 运行 WPS 和 WRF&am…

内核是如何接收网络包的

1、数据如何从网卡到网络协议栈 1.1内核收包的过程 1、数据帧从外部网络到达网卡 2、网卡把数据帧从自己的缓存DMA(拷贝到)和内核共有的RingBuffer上 3、网卡发出硬中断通知CPU 4、CPU响应硬中断,简单处理后发出软中断 5、k’softirqd线程处理软中断,调…

状态估计算法

目录 前言一、贝叶斯滤波二、卡尔曼滤波2.1 KF简介2.2 基本线性模型2.3 KF公式推导2.3.1 预测值2.3.2 先验误差协方差矩阵2.3.3 卡尔曼增益2.3.4 最优估计值2.3.5 后验误差协方差矩阵 2.4 KF算法使用2.5 MATLAB验证2.5 Python验证 三、扩展卡尔曼滤波3.1 EKF原理3.2 MATLAB实现…

基于vue框架的宠物寻回小程序8g7el(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:发布人,宠物分类,宠物信息,接取人,接取信息,完成信息 开题报告内容 基于Vue框架的宠物寻回小程序开题报告 一、研究背景与意义 随着城市化进程的加快和人们生活水平的提高,宠物已成为许多家庭不可或缺的一员。它们不仅为生…

谷歌导入了自我填充密码,不显示

C:\Users\GZDZ\AppData\Local\Google\Chrome\User Data\Default Login Data Login Data-journal 删除上面两个重启就可以了 https://blog.csdn.net/weixin_30940783/article/details/97552679?utm_mediumdistribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandi…

Windows10电脑右下角时间显示到秒

1、打开注册表 快捷键 WIN R 键,输入 regedit 在注册表中找到如下位置 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced 在空白位置右击,新建--DWORD(32位)值(D) 3、将新建的数值名称设置为 ShowSecondsInSystemCloc…

AI绘画与摄影新纪元:ChatGPT+Midjourney+文心一格 共绘梦幻世界

文章目录 一、AI艺术的新时代二、ChatGPT:创意的引擎与灵感的火花三、Midjourney:图像生成的魔法与技术的奇迹四、文心一格:艺术的升华与情感的共鸣五、融合创新:AI绘画与摄影实战的无限可能六、应用场景与实践案例AI艺术的美好未…

【Delphi】知道控件名称(字符串),访问控件

在 Delphi 中,可以使用 RTTI(运行时类型信息) 或其他方法通过对象的名称字符串来访问对象。比如,如果你有一个控件的名称字符串,你希望通过该名称找到并访问实际的控件。 以下是通过 RTTI 以及其他技术(如…

react之jsx基础(1)概念和本质

文章目录 JSX 的基本概念1. **语法**2. **表达式**3. **属性**4. **子元素** JSX 的编译过程1. **转换成 JavaScript**2. **React 元素** JSX 的实际应用1. **组件定义**2. **组件嵌套** 总结 当然,以下是对 JSX 的详细讲解,包括其基本概念、语法、编译过…

【vue element-ui】关于删除按钮的提示框,可一键复制

实现效果: Delete: function (id) {this.$confirm(此操作将永久删除该文件, 是否继续?, 提示, {confirmButtonText: 确定,cancelButtonText: 取消,type: warning,center: true,}).then(() > {Delete(id).then(() > {this.$message({type: success,message: 删…

基于python+django+vue的图书管理系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于pythondjangovueMySQL的图…

Modbus_tcp

目录 一:modbus起源 1.起源 2. 分类: 3. 优势: 4. 应用场景: 5.ModbusTCP特点(掌握): 二、 ModbusTCP的协议 1. 报文头 2. 寄存器 1. 线圈(Coils) 2. 离…