面试系列 - Java代理模式详解

代理模式是一种结构型设计模式,它允许你提供一个代理或替代品来控制对另一个对象的访问。代理对象通常充当客户端和实际目标对象之间的中介,可以用于各种用途,例如延迟加载、访问控制、监视、记录日志等。

一、代理模式包括以下几个关键角色

  1. 抽象主题(Subject): 定义了目标对象和代理对象的共同接口,客户端通过这个接口与目标对象交互。

  2. 具体主题(Real Subject): 实际的目标对象,代理对象所代表的真正业务逻辑。

  3. 代理(Proxy): 包含一个指向具体主题的引用,它实现了与抽象主题相同的接口,并可以在其方法中添加额外的逻辑。

二、静态代理

静态代理是代理模式的一种实现方式,它在编译期间就已经确定了代理关系。在静态代理中,代理类和目标类都必须在编码时已经存在,代理类通过实现与目标类相同的接口或继承与目标类相同的父类来实现代理。

静态代理的基本步骤和示例:

  1. 定义一个接口(或抽象类),用于声明目标对象和代理对象共同拥有的方法。

  2. 创建一个目标类,它实现了上述接口并提供了具体的业务逻辑。

  3. 创建一个代理类,它也实现了上述接口,并包含一个对目标对象的引用。代理类中的方法通常包含了一些额外的逻辑,例如日志记录、性能监测等。

  4. 在客户端代码中,创建目标对象和代理对象,然后通过代理对象调用方法。

下面是一个简单的 Java 示例,演示了静态代理的使用:

// 步骤1:定义接口
interface Subject {void doSomething();
}// 步骤2:创建目标类
class RealSubject implements Subject {public void doSomething() {System.out.println("RealSubject is doing something.");}
}// 步骤3:创建代理类
class Proxy implements Subject {private RealSubject realSubject;public Proxy() {this.realSubject = new RealSubject();}public void doSomething() {// 可以在这里添加额外的逻辑,如日志记录、性能监测等System.out.println("Proxy is doing something.");realSubject.doSomething();}
}// 步骤4:客户端代码
public class StaticProxyExample {public static void main(String[] args) {Subject proxy = new Proxy();proxy.doSomething();}
}

在上面的示例中,Subject 是接口,RealSubject 是目标类,Proxy 是代理类。代理类中的 doSomething 方法在调用目标对象的 doSomething 方法之前,添加了一些额外的逻辑。客户端代码通过代理对象调用方法。

静态代理的优点是简单,易于理解和实现。但它的缺点是每个代理类只能代理一个特定的目标类,如果需要代理多个不同的目标类,就需要创建多个代理类。此外,代理类的维护和扩展也可能会变得复杂。

总之,静态代理是一种简单而直观的代理模式实现方式,适用于特定的场景,但在某些情况下可能会引入大量的代理类。

三、Java 动态代理

java 动态代理是一种在运行时生成代理类的机制,用于代理其他类的方法调用。动态代理通常用于实现横切关注点(cross-cutting concerns)如日志、事务管理、性能监控等。Java 提供了两种主要的动态代理机制:基于接口的 JDK 动态代理和基于类的 CGLIB 动态代理。

1、JDK 动态代理

JDK 动态代理是 Java 标准库中的一部分,它要求被代理的类必须实现一个或多个接口。动态代理的核心类是 java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler

下面是 JDK 动态代理的基本步骤:

  1. 创建一个实现 InvocationHandler 接口的代理处理器类,通常包含一个 invoke 方法,该方法在代理对象的方法被调用时执行所需的逻辑。

  2. 使用 Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) 方法创建代理对象。这个方法接受一个类加载器、一组接口和代理处理器。

  3. 使用代理对象调用方法。当调用代理对象的方法时,invoke 方法将被调用,实际的逻辑由代理处理器定义。

示例代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;interface MyInterface {void doSomething();
}class MyRealObject implements MyInterface {public void doSomething() {System.out.println("Real object is doing something.");}
}class MyInvocationHandler implements InvocationHandler {private Object target;public MyInvocationHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method invocation.");Object result = method.invoke(target, args);System.out.println("After method invocation.");return result;}
}public class DynamicProxyExample {public static void main(String[] args) {MyInterface realObject = new MyRealObject();MyInvocationHandler handler = new MyInvocationHandler(realObject);MyInterface proxyObject = (MyInterface) Proxy.newProxyInstance(realObject.getClass().getClassLoader(),new Class<?>[] { MyInterface.class },handler);proxyObject.doSomething();}
}

2、CGLIB 动态代理

CGLIB(Code Generation Library)是一个强大的代码生成库,它可以在运行时动态生成类和方法。CGLIB 动态代理不要求被代理的类实现接口,它通过生成一个被代理类的子类来实现代理。

下面是 CGLIB 动态代理的基本步骤:

  1. 创建一个 CGLIB 代理对象,通常使用 Enhancer 类。

  2. 为代理对象设置目标类和方法拦截器(通常是一个方法拦截器类或回调函数)。

  3. 调用代理对象的方法,方法拦截器将在目标方法执行前后执行所需的逻辑。

示例代码:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;class MyRealClass {public void doSomething() {System.out.println("Real class is doing something.");}
}class MyMethodInterceptor implements MethodInterceptor {public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method invocation.");Object result = proxy.invokeSuper(obj, args);System.out.println("After method invocation.");return result;}
}public class CglibProxyExample {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MyRealClass.class);enhancer.setCallback(new MyMethodInterceptor());MyRealClass proxyObject = (MyRealClass) enhancer.create();proxyObject.doSomething();}
}

注意:CGLIB 动态代理通常需要引入 CGLIB 库,而 JDK 动态代理是 Java 标准库的一部分。

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

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

相关文章

嵌入式BL304可提供4路RS485/RS232口

BL304网关具有多功能的数据通信和处理设备&#xff0c;具有多种输入和输出接口&#xff0c;支持多种操作系统和应用程序&#xff0c;以及数据库连接。下面我们将详细介绍该产品的特点和功能。 设备提供了多路RS485/RS232接口、CAN口、网口、DI口、PWM口输出以及USB接口&#xf…

肖sir__设计测试用例方法之状态迁移法05_(黑盒测试)

设计测试用例方法之状态迁移法 一、状态迁移图 定义&#xff1a;通过描绘系统的状态及引起系统状态转换的事件&#xff0c;来表示系统的行为 案例&#xff1a; &#xff08;1&#xff09; 订机票案例1&#xff1a; l向航空公司打电话预定机票—>此时机票信息处于“完成”状…

API签名认证的说明及实现

目录 请思考一个问题什么是API签名认证为什么需要API签名认证如何在后端实现签名认证签名认证实现通过 http request header 头传递参数加密方式怎么知道这个签名对不对&#xff1f;怎么防重放&#xff1f; Go 代码实现sign.goservice.goclient.go 请思考一个问题 请思考一个重…

【pytorch】数据加载dataset和dataloader的使用

1、dataset加载数据集 dataset_tranform torchvision.transforms.Compose([torchvision.transforms.ToTensor(),])train_set torchvision.datasets.CIFAR10(root"./train_dataset",trainTrue,transformdataset_tranform,downloadTrue) test_set torchvision.data…

企业网络安全:威胁检测和响应 (TDR)

什么是威胁检测和响应 威胁检测和响应&#xff08;TDR&#xff09;是指识别和消除 IT 基础架构中存在的恶意威胁的过程。它涉及主动监控、分析和操作&#xff0c;以降低风险并防止未经授权的访问、恶意活动和数据泄露&#xff0c;以免它们对组织的网络造成任何潜在损害。威胁检…

Origin绘制彩色光谱图

成果图 1、双击线条打开如下窗口 2、选择“图案”-》颜色-》按点-》映射-》Wavelength 3、选择颜色映射 4、单击填充-》选择加载调色板-》Rainbow-》确定 5、单击级别&#xff0c;设置成从370到780&#xff0c;右侧增量选择2&#xff08;越小&#xff0c;颜色渐变越细腻&am…

linux之perf(2)list事件

Linux之perf(2)list事件 Author&#xff1a;Onceday Date&#xff1a;2023年9月3日 漫漫长路&#xff0c;才刚刚开始… 参考文档: Tutorial - Perf Wiki (kernel.org)perf-list(1) - Linux manual page (man7.org) 1. 概述 perf list用于列出可用的性能事件&#xff0c;这…

Elasticsearch:利用向量搜索进行音乐信息检索

作者&#xff1a;Alex Salgado 欢迎来到音乐信息检索的未来&#xff0c;机器学习、向量数据库和音频数据分析融合在一起&#xff0c;带来令人兴奋的新可能性&#xff01; 如果你对音乐数据分析领域感兴趣&#xff0c;或者只是热衷于技术如何彻底改变音乐行业&#xff0c;那么本…

oracle10和11功能说明比较

Oracle 10g/11g的特点和优势 首先&#xff0c;Oracle 10g/11g具有以下几个特点&#xff1a; 1. 可靠性和稳定性&#xff1a;Oracle 10g采用了多种技术来确保数据的可靠性和稳定性&#xff0c;如ACID事务处理和数据备份与恢复机制。它还提供了高可用性的解决方案&#xff0c;如…

记本地新建一个gradle方式springboot项目过程

打算使用gradle在idea新建个springboot项目&#xff0c;然后坑很多&#xff0c;记录一下 原来我的idea应该是社区版&#xff0c;新建项目时候没有可以选择spring相关配置&#xff0c;然后卸载了重装&#xff0c;之前问题是启动是启动起来了&#xff0c;但是状态栏那边一直显示…

手写Spring:第8章-初始化和销毁方法

文章目录 一、目标&#xff1a;初始化和销毁方法二、设计&#xff1a;初始化和销毁方法三、实现&#xff1a;初始化和销毁方法3.1 工程结构3.2 Spring应用上下文和Bean对象扩展初始化和销毁类图3.3 定义初始化和销毁方法的接口3.3.1 定义初始化接口3.3.2 定义销毁接口3.3.3 定义…

机器学习基础算法--回归类型和评价分析

目录 1.数据归一化处理 2.数据标准化处理 3.Lasso回归模型 4.岭回归模型 5.评价指标计算 1.数据归一化处理 """ x的归一化的方法还是比较多的我们就选取最为基本的归一化方法 x(x-x_min)/(x_max-x_min) """ import numpy as np from sklea…

CSS构建基础(二)选择器

在CSS中&#xff0c;选择器用于定位我们想要样式化的网页上的HTML元素。有各种各样的CSS选择器可用&#xff0c;允许在选择要样式化的元素时实现细粒度的精度。在本文及其子文章中&#xff0c;我们将详细介绍不同的类型&#xff0c;了解它们是如何工作的。 1、什么是选择器? …

浏览器跨域

相关问题 什么是跨域为什么会跨域为什么会有跨域的限制怎么解决跨域 回答关键点 CORS和同源策略 跨域问题的来源是浏览器为了请求安全而引入的基于同源策略的安全特性。当页面和请求的协议、主机名或端口不同时&#xff0c;浏览器判定两者不同源&#xff0c;即为跨域请求。需…

Springboot开发时,对前端的请求参数,后端用于接受的实体类有没有必要校验为null?

首先给出结论&#xff1a;不用校验为NULL,如果null,Springboot会直接抛异常而不是返回NUll。只需要对其中的属性判断是否null 问题代码如下&#xff1a; public R<Boolean> addzbsz (RequestBody RequestzbszAdd requestzbszAdd) {if ( requestzbszAddnull){return true…

PMP备考全攻略,看这一份就够了!

免费送备考资料。 Project Management Professional (PMP) - 项目管理专业人士,简称PMP。是项目管理专业人士资格认证由项目管理学会和 PMI 发起&#xff0c;严格评估管理项目人员知识技能是否具有高品质的资格认证考试。 简单来说&#xff0c;PMP是美国PMI发起的评估项目管理…

PyTorch 深度学习实践 第10讲刘二大人

总结&#xff1a; 1.输入通道个数 等于 卷积核通道个数 2.卷积核个数 等于 输出通道个数 1.单通道卷积 以单通道卷积为例&#xff0c;输入为&#xff08;1,5,5&#xff09;&#xff0c;分别表示1个通道&#xff0c;宽为5&#xff0c;高为5。假设卷积核大小为3x3&#xff0c…

在不同操作系统上如何安装符号表提取工具(eu-strip)

前言 C开发的小伙伴都知道符号表在调试和解决崩溃时扮演着非常重要的角色&#xff0c;那么如何提取和保存发布应用程序的符号表就变得非常重要。今天就来聊一下如何在不同的操作系统上使用eu-strip提取应用程序中的符号表信息。 正文 问题 如何在不同操作系统上安装符号表提…

定时任务实现方案总结

一、概述 定时任务的作用是在设定的时间和日期后自动执行任务&#xff0c;执行任务的周期既能是单次也能是周期性。 本文重点说明Timer、ScheduledThreadPoolExecutor、Spring Task、Quartz等几种定时任务技术方案。 二、Timer JDK自带的Timer是最古老的定时任务实现方式了。…

【Vue3-Vite】Vite配置--路径别名配置

路径别名配置 使用 代替 src Vite配置 // vite.config.ts import {defineConfig} from vite import vue from vitejs/plugin-vueimport path from pathexport default defineConfig({plugins: [vue()],resolve: {alias: {"": path.resolve("./src") // …