设计模式之房产中介——代理模式

手撕设计模式之房产中介——代理模式

1.业务需求

​ 大家好,我是菠菜啊,好久不见,今天给大家带来的是——代理模式。老规矩,在介绍这期内容前,我们先来看看这样的需求:我们有一套房产需要出售,但是我们抽不开身去带客户看房对接而且获客方式有限,我们该怎么实现?

在这里插入图片描述

2.代码实现

Talk is cheap,show me your code.

初版实现思路:

​ 既然自己没时间、没客源,可以找个中间人不就行了,这个中间人就是房产代理。

初版代码如下:

//房屋售卖接口
public interface HouseSaleService {void saleHouse();
}
//房东类
public class HouseOwner implements HouseSaleService {@Overridepublic void saleHouse() {System.out.println("我是房东,我签订售房合同");System.out.println("我是房东,售出房源");}
}
//房产中介类
public class ProxyHouse implements HouseSaleService{private HouseSaleService houseSaleService;public ProxyHouse(HouseSaleService houseSaleService) {this.houseSaleService = houseSaleService;}@Overridepublic void saleHouse() {System.out.println("房产中介——开始带客户看房");houseSaleService.saleHouse();System.out.println("房产中介——房源售出,结束");}
}
public class Client {public static void main(String[] args) {HouseSaleService houseSaleService = new HouseOwner();HouseSaleService proxyHouse = new ProxyHouse(houseSaleService);proxyHouse.saleHouse();}
}

输出结果:

在这里插入图片描述

实现代码结构图:

在这里插入图片描述

这个实现过程其实就是代理设计模式,属于代理模式中的静态代理。

3.需求升级

我们现在不是房东了,我们现在是一个中介平台,平台上有千千万万个房东和中介,如果还是实现上述代理买房的需求,交易的流程是一样的,该怎么做呢?不会添加那么多房产代理人吧。

//售房调用处理器类
public class HouseSaleInvocationHandler implements InvocationHandler {//房东private Object target;public HouseSaleInvocationHandler(Object target){this.target = target;}//三个参数:代理对象实例、方法对象(Method)和参数数组@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("动态生成房产中介代理——开始带客户看房");Object result =  method.invoke(target, args);System.out.println("动态生成房产中介代理——房源售出,结束");return result;}//创建动态代理对象public static Object newProxyInstance(Object target){//传入目标对象的类加载器,目标对象实现的接口,调用处理器return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new HouseSaleInvocationHandler(target));}
}
//客户端(动态代理)
public class Client2 {public static void main(String[] args) {HouseSaleService houseSaleService = (HouseSaleService)HouseSaleInvocationHandler.newProxyInstance(new HouseOwner());houseSaleService.saleHouse();}
}

​ 执行结果:

在这里插入图片描述

​ 上述代码可以实现一套代理流程动态为多个房东生成房产代理,无需手动一个个手动创建。有没有同学觉得很熟悉,看过jdk源码的同学应该很熟悉(详细实现过程见下方源码剖析部分),它是利用java.lang.reflect包下的ProxyInvocationHandler核心类实现动态代理机制的,又称JDK的动态代理。实现原理:在运行代码时利用反射动态生成代理类,将目标方法的调用都转发到InvocationHandler的invoke方法,利用反射机制执行目标方法并插入增强逻辑。

核心流程如下:

在这里插入图片描述

思考:

​ 上述代码只能解决实现过售卖接口的房东需求,那些没通过实现售卖接口的个人房东好像满足不了他们的需求,所以又有另一种实现方式。

个人房东代码改造:

pom依赖:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
//cglib代理类
public class CglibProxyHouse {//获取代理对象public static Object getInstance(Object target) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());// 设置目标类enhancer.setCallback(new CglibMethodInterceptor());// 设置方法拦截器return enhancer.create();}}
//cglib方法拦截增强类
public class CglibMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("动态生成房产中介代理———开始带客户看房-CglibProxyHouse");Object result=methodProxy.invokeSuper(proxy, args);// 调用父类(目标类)的方法System.out.println("动态生成房产中介代理———房源售出,结束-CglibProxyHouse");return result;}
}
//个人房东
public class OtherHouseOwner  {public  void saleHouse() {System.out.println("我是个人房东,我签订售房合同");System.out.println("我是个人房东,售出房源");}
}
//Cglib动态代理测试类
public class Client3 {public static void main(String[] args) {OtherHouseOwner houseOwner = (OtherHouseOwner)  CglibProxyHouse.getInstance(new OtherHouseOwner());houseOwner.saleHouse();}
}

运行结果:

在这里插入图片描述

​ 上述代码实现了个人房东动态代理卖房需求,个人房东无需实现响应接口。它利用net.sf.cglib.proxy包下的EnhancerMethodInterceptor核心类实现动态代理机制的,又称CGLIB动态代理CGLIB通过继承目标类并重写非final方法,在运行时使用ASM字节码技术动态生成代理子类,将方法调用委托给MethodInterceptor实现增强逻辑,并借助FastClass机制通过方法索引直接调用提升性能。

在这里插入图片描述

动态代理对比:

特性JDK动态代理CGLIB
代理方式实现接口继承目标类
性能反射调用,较慢FastClass调用,较快
依赖无第三方库需CGLIB库
目标类要求必须实现接口不能是final类/方法
初始化开销大(生成两个FastClass)
方法调用模式通过InvocationHandler通过MethodInterceptor

4.定义

​ 代理设计模式是一种结构型设计模式,其核心思想是提供一个代理对象来控制对原始对象的访问。代理充当原始对象的中间层,允许在访问原始对象前后添加额外逻辑,而无需修改原始对象本身。

组成部分如下:

  1. 代理对象(Proxy)

    • 实现与原始对象相同的接口
    • 持有对原始对象的引用
    • 控制客户端对原始对象的访问
  2. 原始对象(Real Subject)

    • 实际执行业务逻辑的目标对象
  3. 抽象接口(Subject)

    • 定义代理和原始对象的共同接口,确保二者可互换使用

      在这里插入图片描述

5.应用场景

场景类型典型用途实例
虚拟代理延迟创建开销大的对象图片懒加载:代理先显示占位图,真正需要时才加载高清图片
远程代理隐藏远程调用的复杂性RPC框架:代理封装网络通信细节,客户端像调用本地对象一样调用远程服务
保护代理控制访问权限权限校验:代理验证用户权限后再允许访问敏感操作
缓存代理缓存昂贵操作的结果API请求缓存:代理缓存计算结果,重复请求直接返回结果,避免重复计算
日志代理记录访问日志审计系统:代理在方法调用前后记录日志和时间戳
智能引用代理管理对象生命周期自动释放资源:代理统计对象引用计数,引用归零时自动销毁对象

适用性总结

✅ 需要隔离客户端与复杂系统(如远程服务)
✅ 需要延迟初始化高开销对象
✅ 需添加访问控制或安全层
✅ 需透明添加日志、监控等横切关注点
✅ 需实现智能引用(如对象池、缓存)

典型场景:

​ Spring AOP 的底层机制完全基于代理模式实现,通过动态代理在运行时生成代理对象,将切面逻辑(如日志、事务等)织入目标方法中。其具体实现分为两种机制:JDK 动态代理CGLIB 代理,由 Spring 根据目标类的特性自动选择或通过配置强制指定。目标类实现了接口,使用JDK 动态代理;目标类未实现接口,CGLIB 代理,也可强制指定。

源码剖析

1.JDK动态代理

1.1 Proxy.newProxyInstance() 入口方法
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) {// 1. 验证接口和处理器有效性Objects.requireNonNull(h);final Class<?>[] intfs = interfaces.clone();// 2. 获取或生成代理类Class<?> cl = getProxyClass0(loader, intfs);try {// 3. 获取代理类构造器final Constructor<?> cons = cl.getConstructor(constructorParams);// 4. 创建代理实例return cons.newInstance(new Object[]{h});} catch (IllegalAccessException|InstantiationException e) {// 异常处理...}
}
1.2 代理类生成机制(getProxyClass0)
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {// 1. 接口数量限制(最多65535个)if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}// 2. 从缓存获取或生成代理类return proxyClassCache.get(loader, interfaces);
}

代理类缓存使用WeakCache实现,核心逻辑在ProxyClassFactory中:

private static final class ProxyClassFactoryimplements BiFunction<ClassLoader, Class<?>[], Class<?>>
{@Overridepublic Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {// 1. 生成唯一代理类名long num = nextUniqueNumber.getAndIncrement();String proxyName = proxyPkg + proxyClassNamePrefix + num;// 2. 生成代理类字节码byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);// 3. 定义代理类return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);}
}
1.3 代理类字节码生成(ProxyGenerator)

generateProxyClass方法生成代理类的字节码,其核心逻辑如下:

public static byte[] generateProxyClass(final String name,Class<?>[] interfaces,int accessFlags) {ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);// 真正生成字节码final byte[] classFile = gen.generateClassFile();// 可选项:保存生成的字节码到文件(调试用)if (saveGeneratedFiles) {java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {public Void run() {try {FileOutputStream file = new FileOutputStream(dotToSlash(name) + ".class");file.write(classFile);file.close();} catch (IOException e) { /* 忽略 */ }return null;}});}return classFile;
}
1.4 生成的代理类结构(反编译示例)

假设我们代理HouseSaleService接口,生成的$Proxy0.class反编译后:

public final class $Proxy0 extends Proxy implements HouseSaleService {private static Method m1;  // hashCode()private static Method m2;  // equals()private static Method m3;  // toString()private static Method m4;  // saleHouse()static {try {m1 = Class.forName("java.lang.Object").getMethod("hashCode");m2 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m3 = Class.forName("java.lang.Object").getMethod("toString");m4 = Class.forName("com.example.HouseSaleService").getMethod("saleHouse");} catch (NoSuchMethodException e) { /* 处理异常 */ }}public $Proxy0(InvocationHandler h) {super(h);  // 调用Proxy的构造函数}public final void saleHouse() {try {// 关键:调用InvocationHandler的invoke方法super.h.invoke(this, m4, null);} catch (RuntimeException | Error e) {throw e;} catch (Throwable e) {throw new UndeclaredThrowableException(e);}}// 其他Object方法实现类似...
}

代理对象实现目标接口,方法调用里其实还是调用InvocationHandler的invoke方法。

2.CGLIB动态代理

2.1Enhancer 入口类

创建代理对象通常使用以下代码:

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetClass.class); // 设置目标类
enhancer.setCallback(new MyMethodInterceptor()); // 设置回调(拦截器)
TargetClass proxy = (TargetClass) enhancer.create(); // 生成代理对象
2.2 enhancer.create() 方法调用链
// Enhancer.java
public Object create() {// 关键:不使用参数return createHelper();
}private Object createHelper() {// 1. 验证回调类型preValidate();// 2. 生成代理类Class<?> proxyClass = createClass();// 3. 创建代理实例return createUsingReflection(proxyClass);
}
2.3 代理类生成(createClass)
// AbstractClassGenerator.java
protected Class<?> createClass() {// 使用字节码生成器生成字节码byte[] b = strategy.generate(this);// 定义类return ReflectUtils.defineClass(getClassName(), b, loader);
}
2.4 字节码生成核心:Enhancer.generateClass

CGLIB通过ASM库直接操作字节码,关键逻辑在Enhancer.generateClass方法中:

// Enhancer.java
public void generateClass(ClassVisitor v) {// 1. 创建类结构ClassEmitter ce = new ClassEmitter(v);ce.begin_class(/* 版本号 */, ACC_PUBLIC, getClassName(), getSuperclass(), getInterfaces(), "<generated>");// 2. 添加字段ce.declare_field(ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);ce.declare_field(ACC_PRIVATE, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);ce.declare_field(ACC_PRIVATE, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);// 3. 生成构造函数generateConstructor(ce);// 4. 生成回调设置方法generateSetCallbacks(ce);generateSetCallback(ce);generateGetCallback(ce);// 5. 重写目标方法for (Method method : getMethods()) {generateMethod(ce, method);}ce.end_class();
}
2.5 方法生成逻辑(generateMethod)
// Enhancer.java
private void generateMethod(ClassEmitter ce, Method method) {// 1. 创建方法签名Signature sig = ReflectUtils.getSignature(method);// 2. 创建方法体CodeEmitter e = ce.begin_method(ACC_PUBLIC, sig, null);// 3. 获取回调e.load_this();e.getfield(CALLBACK_FIELD);// 4. 检查回调是否存在Label noCallback = e.make_label();e.dup();e.ifnull(noCallback);// 5. 准备调用参数e.push(method);e.create_arg_array();e.push(methodProxy);// 6. 调用拦截器e.invoke_interface(METHOD_INTERCEPTOR_TYPE, new Signature("intercept", Type.OBJECT, new Type[]{TYPE_OBJECT, TYPE_METHOD, TYPE_OBJECT_ARRAY, TYPE_METHOD_PROXY}));// 7. 结果处理e.unbox_or_zero(e.getReturnType());e.return_value();// 8. 没有回调时的处理e.mark(noCallback);e.pop();// 调用原始方法super.generateMethod(ce, method);e.return_value();e.end_method();
}
2.6 生成的代理类结构(反编译示例)

使用CGLIB代理后生成的代理类大致如下:

public class OtherHouseOwner$$EnhancerByCGLIB$$12345678 extends OtherHouseOwner implements Factory {private MethodInterceptor interceptor;private static final Method CGLIB$saleHouse$0$Method;private static final MethodProxy CGLIB$saleHouse$0$Proxy;static {// 初始化目标方法和代理方法CGLIB$saleHouse$0$Method = ReflectUtils.findMethods(new String[]{"saleHouse", "()V"}).get(0);CGLIB$saleHouse$0$Proxy = MethodProxy.create(OtherHouseOwner.class, OtherHouseOwner$$EnhancerByCGLIB$$12345678.class, "()V", "saleHouse", "CGLIB$saleHouse$0");}// 重写目标方法public final void saleHouse() {MethodInterceptor tmp = this.interceptor;if (tmp == null) {super.saleHouse(); // 如果未设置拦截器,直接调用父类方法} else {// 调用拦截器的intercept方法tmp.intercept(this, CGLIB$saleHouse$0$Method, new Object[0], CGLIB$saleHouse$0$Proxy);}}// 原始方法的直接调用(避免拦截)final void CGLIB$saleHouse$0() {super.saleHouse();}// 其他方法...
}

如果未设置拦截器,直接调用父类方法;如果有设置方法拦截器,直接回调拦截器方法。

2.7 MethodProxy 工作原理

MethodProxy是CGLIB高效调用的关键,它通过生成两个FastClass(目标类FastClass和代理类FastClass)实现快速方法调用。

// MethodProxy.java
public Object invoke(Object obj, Object[] args) throws Throwable {try {// 使用目标类的FastClass直接调用原始方法return fastClass.invoke(targetIndex, obj, args);} catch (InvocationTargetException e) {throw e.getTargetException();}
}public Object invokeSuper(Object obj, Object[] args) throws Throwable {try {// 使用代理类的FastClass调用代理类中的原始方法(即CGLIB$xxx方法)return fastClass.invoke(superIndex, obj, args);} catch (InvocationTargetException e) {throw e.getTargetException();}
}
2.8 FastClass 机制

FastClass为每个方法分配一个索引(index),通过索引直接调用方法,避免反射开销。

// 生成的TargetFastClass
public Object invoke(int index, Object obj, Object[] args) {OtherHouseOwner otherHouseOwner = (OtherHouseOwner) obj;switch (index) {case 0:otherHouseOwner.saleHouse();return null;// 其他方法...}
}// 生成的ProxyFastClass
public Object invoke(int index, Object obj, Object[] args) {OtherHouseOwner$$EnhancerByCGLIB proxy = (OtherHouseOwner$$EnhancerByCGLIB) obj;switch (index) {case 0:proxy.CGLIB$saleHouse$0();return null;// 其他方法...}
}

法,避免反射开销。

// 生成的TargetFastClass
public Object invoke(int index, Object obj, Object[] args) {OtherHouseOwner otherHouseOwner = (OtherHouseOwner) obj;switch (index) {case 0:otherHouseOwner.saleHouse();return null;// 其他方法...}
}// 生成的ProxyFastClass
public Object invoke(int index, Object obj, Object[] args) {OtherHouseOwner$$EnhancerByCGLIB proxy = (OtherHouseOwner$$EnhancerByCGLIB) obj;switch (index) {case 0:proxy.CGLIB$saleHouse$0();return null;// 其他方法...}
}

技术需要沉淀,同样生活也是~
个人链接:博客,欢迎一起交流

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

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

相关文章

Unity进阶课程【六】Android、ios、Pad 终端设备打包局域网IP调试、USB调试、性能检测、控制台打印日志等、C#

Unity打包 Android、ios、Pad 终端设备局域网IP调试、USB调试 今天咱们继续进阶课程&#xff0c;定期更新&#xff0c;有想学习的不懂的地方也可以告诉我。 提示&#xff1a;内容纯个人编写&#xff0c;欢迎评论点赞&#xff0c;来指正我。 文章目录 Unity打包 Android、ios、P…

c++中的mutex同步机制与多线程同步实现

C 中的 std::mutex 与多线程同步 在多线程编程中&#xff0c;互斥锁&#xff08;Mutex&#xff09; 是一种同步机制&#xff0c;用于保护共享资源&#xff08;如变量、数据结构&#xff09;免受数据竞争&#xff08;Data Race&#xff09;的影响。C 标准库中的 std::mutex 提供…

网络安全2023—新安全新发展

关于绿盟科技 绿盟科技集团股份有限公司(以下简称绿盟科技),成立于 2000 年 4 月,总部位于北京。公司于 2014 年 1 月 29 日在深圳证券交易所创业板上市,证券代码:300369。绿盟科技在国内设有 50余个分支机构,为政府、金融、运营商、能源、交通、科教文卫等行业用户与各…

WebSocket扫盲

WebSocket 是一种网络通信协议&#xff0c;它允许在单个 TCP 连接上进行全双工、双向的实时通信。它是为了解决传统 HTTP 协议在实时交互应用中的局限性而设计的。 核心概念和特点 解决 HTTP 的痛点&#xff1a; 单向性&#xff1a; HTTP 是请求-响应模式。客户端发起请求&…

Springboot整合高德地图

1.登录高德开放平台 高德开放平台 | 高德地图API 2.获取密钥key 1.点击控制台 2.创建新应用 3.添加key 4.创建key 5.获取key 3.java整合 1.高德配置类 package com.thk.controller.map;import org.springframework.beans.factory.annotation.Value; import org.springfram…

【SQL知识】PDO 和 MySQLi 的区别

目录 简介 主要区别 预处理语句示例比较 PDO 示例 MySQLi 示例 选择建议 简介 PDO (PHP Data Objects) 和 MySQLi (MySQL Improved) 都是 PHP 中用于数据库操作的扩展&#xff0c;都支持预处理语句&#xff0c;但有一些重要区别&#xff1a; 主要区别 数据库支持 PDO&am…

python打卡 DAY 45 Tensorboard使用介绍

目录 一、TensorBoard 发展历史与原理 1. 演进历程 2. 核心架构原理 二、TensorBoard 核心功能操作 1. 基础配置方法 2. 常用功能速查表 三、CIFAR10 实战演示 1. MLP 模型监控配置 2. CNN 特征可视化 四、TensorBoard 高级功能 1. 超参数调优 2. 3D点云可视化 五、…

Swift 中 Result 类型全解析:从基础到进阶

在现代 iOS 开发中&#xff0c;Swift 的 Result 类型是处理同步与异步错误的一大利器。相比传统的 throws / do-catch 语法&#xff0c;它更清晰、结构化&#xff0c;也更易于组合式编程。 本文将带你从 Result 的基础定义出发&#xff0c;逐步深入其在实际项目中的多种应用&am…

Github 2025-06-28 Rust开源项目日报 Top10

根据Github Trendings的统计,今日(2025-06-28统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Rust实现的非官方Bitwarden兼容服务器 创建周期:2317 天开发语言:Rust协议类型:GNU Affero General Public License v3.0Star数量…

python 写一个判断文本中是否有手机号的函数,并提取出文本中的手机号

我们需要判断文本中是否有手机号&#xff0c;并提取出手机号。 中国大陆的手机号规则&#xff1a; 1. 通常为11位数字。 2. 目前手机号段分配如下&#xff1a; - 移动号段&#xff1a;134(0-8)、135、136、137、138、139、147、148、150、151、152、157、158、159、172、178、1…

作物生长模型Oryza V3实战12:drate程序详解

drate(v2).exe,可以通过观察移植日、穗部分化、开花和成熟的物候日期(即日和年),DRATE(v2)用于校准四个阶段的发展速率:幼苗期(DVRJ,oCday-1)、光周期敏感期(DVRI,oCday-1)、穗部发育期(DVRP,oCday-1)和生殖期(DVRR,oCday-1)。 一 准备输入文件 1、准备.crp,.…

利用视觉-语言模型搭建机器人灵巧操作的支架

25年6月来自斯坦福和德国卡尔斯鲁厄理工的论文“Scaffolding Dexterous Manipulation with Vision-Language Models”。 灵巧机械手对于执行复杂的操作任务至关重要&#xff0c;但由于演示收集和高维控制的挑战&#xff0c;其训练仍然困难重重。虽然强化学习 (RL) 可以通过在模…

面试拷打-20250701

memcopy和memmov 详细解释 示例1&#xff1a;不重叠的内存区域 正常复制。 示例2&#xff1a;重叠的内存区域 原始数据&#xff1a;src2是一个包含字符串"HelloWorld"的字符数组。使用memcpy&#xff1a; memcpy(src2 2, src2, 5);试图将src2中的前5个字符复制…

什么是 BigKey?

Redis BigKey 深度解析&#xff1a;识别、危害与优化方案 什么是 BigKey&#xff1f; 在 Redis 中&#xff0c;BigKey 是指存储大量数据的单个键&#xff0c;这些键通常具有异常大的内存占用或包含大量元素。BigKey 不是由数据类型定义&#xff0c;而是由其资源消耗决定的。 …

量化选股策略 聚宽

# 量化选股策略完整分析与优化建议 ## 策略整体架构分析 这个量化交易策略主要由以下几个核心部分组成&#xff1a; 1. **初始化设置**&#xff1a;配置基准指数、交易参数和全局变量 2. **选股逻辑**&#xff1a;通过财务指标筛选优质股票 3. **股票过滤**&#xff1a;排除…

Python 数据分析:numpy,抽提,布尔索引2。

目录 1 示例代码2 欢迎纠错3 论文写作/Python 学习智能体------以下关于 Markdown 编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右S…

解决leetcode第3597题分割字符串

3597. 分割字符串 难度&#xff1a;中等 问题描述&#xff1a; 给你一个字符串 s&#xff0c;按照以下步骤将其分割为 互不相同的段 &#xff1a; 从下标 0 开始构建一个段。 逐字符扩展当前段&#xff0c;直到该段之前未曾出现过。 只要当前段是唯一的&#xff0c;就将其…

电源芯片之DCDC初探索ING

1. 概述 DC-DC转换器的意思是直流变直流&#xff08;不同的直流电源值得转换&#xff09;&#xff0c;是一种在直流电路中将一个电压值的电能变为另一个电压值的电能装置。 DC-DC转换器一般由控制芯片、电感线圈、二极管、三极管、电容器构成。 2. 基本拓扑结构 2.1 非隔离…

JavaEE:分布式session

一、使用Redis存储分布式session&#xff1a; 1.SpringBoot整合Redis&#xff0c;见如下地址&#xff1a; JavaEE&#xff1a;SpringBoot整合Redis_a526001650a-CSDN博客 2.代码实现分布式session存储(此处以token为例)&#xff1a; Autowired private RedisTemplate<St…

OpenCV CUDA模块设备层-----“大于阈值设为零” 的图像处理函数 thresh_to_zero_inv_func()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 OpenCV 的 CUDA 模块&#xff08;cudev&#xff09; 中的一个仿函数生成器&#xff0c;用于创建一个 “大于阈值设为零” 的图像处理函数对象。 …