专项攻克——重写 Redis 依赖包方法的 6 种实现方式

发布时间:2026/10/29 7:40:44

专项攻克——重写 Redis 依赖包方法的 6 种实现方式 文章目录方式一继承重写最简单优先考虑示例重写 Jedis 的 set 方法示例重写 Spring Data Redis 的 RedisTemplate方式二装饰器模式组合比继承更灵活示例包装 RedisTemplate 的 opsForValue方式三Spring AOP 切面拦截无侵入推荐用于增强示例拦截 RedisTemplate 的所有 set 操作方式四同包同类名覆盖类加载优先级黑科技示例覆盖 Jedis 的某个类方式五Java Agent 字节码增强终极方案示例用 ByteBuddy 拦截 Jedis 的 set 方法方式六动态代理JDK 动态代理 / CGLIB示例JDK 动态代理包装 JedisCommands 接口方案选择决策树面试口述标准答案先确认你用的是哪个 Redis 客户端Jedis / Lettuce / Spring Data Redis / Redisson不同方式适用场景不同。下面按推荐优先级逐一给出可落地代码。方式一继承重写最简单优先考虑适用条件目标类不是final目标方法不是final/static/private。示例重写 Jedis 的set方法import redis.clients.jedis.Jedis; public class CustomJedis extends Jedis { public CustomJedis(String host, int port) { super(host, port); } Override public String set(String key, String value) { // 前置增强比如加日志、统计、权限校验 System.out.println(自定义set方法被调用key key); // 调用原方法 String result super.set(key, value); // 后置增强 System.out.println(set执行结果 result); return result; } }使用try (CustomJedis jedis new CustomJedis(localhost, 6379)) { jedis.set(key1, value1); // 走你重写的方法 }示例重写 Spring Data Redis 的 RedisTemplateimport org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; public class CustomRedisTemplateK, V extends RedisTemplateK, V { Override public ValueOperationsK, V opsForValue() { // 包装一层对 opsForValue 返回的对象做增强 return new CustomValueOperations(super.opsForValue()); } }坑点如果类是final比如 Lettuce 的很多类此方式不可用如果方法是static不能重写只能隐藏不推荐框架内部如果直接 new 原类而不是用你的子类重写不生效方式二装饰器模式组合比继承更灵活适用条件目标类是final无法继承或只想增强部分方法。示例包装 RedisTemplate 的 opsForValueimport org.springframework.data.redis.core.ValueOperations; import java.util.concurrent.TimeUnit; public class CustomValueOperationsK, V implements ValueOperationsK, V { private final ValueOperationsK, V delegate; // 被包装的原对象 public CustomValueOperations(ValueOperationsK, V delegate) { this.delegate delegate; } Override public void set(K key, V value) { System.out.println(装饰器拦截 setkey key); delegate.set(key, value); // 委托给原对象 } Override public Boolean setIfAbsent(K key, V value, long timeout, TimeUnit unit) { System.out.println(装饰器拦截 setIfAbsentkey key); return delegate.setIfAbsent(key, value, timeout, unit); } // 其余方法全部委托给 delegate不做改动 Override public V get(Object key) { return delegate.get(key); } Override public Long increment(K key) { return delegate.increment(key); } // ... 接口里所有方法都要实现逐个委托 }Spring 中注入使用Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } // 直接暴露包装后的 ValueOperations Bean public ValueOperationsString, Object customValueOperations(RedisTemplateString, Object redisTemplate) { return new CustomValueOperations(redisTemplate.opsForValue()); } }坑点接口方法很多时实现起来繁琐可以用 LombokDelegate简化如果有多个重载方法每个都要单独处理方式三Spring AOP 切面拦截无侵入推荐用于增强适用条件只想加日志、监控、缓存、权限等横切逻辑不改原方法核心逻辑。示例拦截 RedisTemplate 的所有 set 操作import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; Aspect Component public class RedisMethodAspect { // 拦截 RedisTemplate 中所有以 set 开头的方法 Around(execution(* org.springframework.data.redis.core.RedisTemplate.set*(..))) public Object aroundSetMethods(ProceedingJoinPoint pjp) throws Throwable { long start System.currentTimeMillis(); String methodName pjp.getSignature().getName(); Object[] args pjp.getArgs(); System.out.println([Redis AOP] 方法 methodName , 参数 java.util.Arrays.toString(args)); try { Object result pjp.proceed(); // 执行原方法 long cost System.currentTimeMillis() - start; System.out.println([Redis AOP] 执行成功耗时 cost ms); return result; } catch (Throwable e) { System.out.println([Redis AOP] 执行失败: e.getMessage()); throw e; } } // 也可以拦截具体某个方法 Around(execution(* org.springframework.data.redis.core.ValueOperations.set(..))) public Object aroundValueSet(ProceedingJoinPoint pjp) throws Throwable { // 你的增强逻辑 return pjp.proceed(); } }坑点Spring AOP 只能拦截 Spring 容器管理的 Bean自己new出来的对象不生效只能拦截public方法CGLIB 可以拦截 protected但不推荐同类内部方法调用this.xxx()不会触发 AOP如果要完全替换方法逻辑不调用原方法不调用pjp.proceed()即可但要自己返回正确类型方式四同包同类名覆盖类加载优先级黑科技适用条件目标类是final 方法是final且你想彻底替换整个类的实现。原理在你的项目源码中创建一个包名、类名完全相同的类编译后你的 class 会优先被类加载器加载因为 target/classes 在 classpath 中排在依赖 jar 前面。示例覆盖 Jedis 的某个类假设要覆盖redis.clients.jedis.Jedis类// 在你的项目 src/main/java 下创建完全相同的包路径 package redis.clients.jedis; // 包名必须完全一致 public class Jedis { // 类名必须完全一致 // 重写整个类的实现或者只改你要的方法 // 注意这个类会完全替换 jar 包里的 Jedis 类 public String set(String key, String value) { System.out.println(完全替换的set方法); // 你的实现... return OK; } // 其他方法也要实现否则调用会报错 }坑点极多慎用这是完全替换不是增强原类的所有方法你都得自己实现依赖包升级后原类结构变了你的覆盖类可能直接报错团队协作时其他人很难发现这个黑科技维护成本极高如果有类加载器隔离比如 Tomcat、OSGi可能不生效除非万不得已否则不要用这种方式方式五Java Agent 字节码增强终极方案适用条件需要在运行时动态修改任意类包括 final 类、JDK 类且无法通过其他方式实现。工具ByteBuddy推荐、ASM、Javassist示例用 ByteBuddy 拦截 Jedis 的 set 方法import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; import java.lang.instrument.Instrumentation; public class RedisAgent { public static void premain(String agentArgs, Instrumentation inst) { new AgentBuilder.Default() .type(ElementMatchers.named(redis.clients.jedis.Jedis)) .transform((builder, typeDescription, classLoader, module, protectionDomain) - builder.method(ElementMatchers.named(set) .and(ElementMatchers.takesArguments(String.class, String.class))) .intercept(Advice.to(RedisSetAdvice.class)) ) .installOn(inst); } }import net.bytebuddy.asm.Advice; public class RedisSetAdvice { Advice.OnMethodEnter public static void enter(Advice.Argument(0) String key, Advice.Argument(1) String value) { System.out.println([ByteBuddy] 进入set方法key key , value value); } Advice.OnMethodExit(onThrowable Exception.class) public static void exit(Advice.Return String result, Advice.Thrown Throwable throwable) { if (throwable ! null) { System.out.println([ByteBuddy] set方法异常: throwable.getMessage()); } else { System.out.println([ByteBuddy] set方法返回: result); } } }使用方式# 打成 agent jar启动时附加 java -javaagent:redis-agent.jar -jar your-app.jar坑点复杂度高需要理解字节码和类加载机制调试困难出问题很难排查对 JDK 版本敏感不同 JDK 版本的字节码格式可能有差异一般只有中间件、APM 工具如 SkyWalking、Pinpoint才会用方式六动态代理JDK 动态代理 / CGLIB适用条件目标类实现了接口用 JDK 动态代理没有接口用 CGLIB。示例JDK 动态代理包装 JedisCommands 接口import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCommands; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class RedisProxyFactory { public static JedisCommands createProxy(Jedis jedis) { return (JedisCommands) Proxy.newProxyInstance( jedis.getClass().getClassLoader(), new Class?[]{JedisCommands.class}, new RedisInvocationHandler(jedis) ); } static class RedisInvocationHandler implements InvocationHandler { private final Object target; public RedisInvocationHandler(Object target) { this.target target; } Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (set.equals(method.getName())) { System.out.println([动态代理] 拦截set方法参数 java.util.Arrays.toString(args)); } return method.invoke(target, args); } } }使用Jedis jedis new Jedis(localhost, 6379); JedisCommands proxy RedisProxyFactory.createProxy(jedis); proxy.set(key, value); // 走代理坑点JDK 动态代理只能代理接口不能代理具体类CGLIB 不能代理 final 类和 final 方法代理对象和原对象是两个对象框架内部如果用原对象代理不生效方案选择决策树你想做什么 ├── 只加日志/监控/统计等横切逻辑 → 方式三Spring AOP推荐 ├── 改方法逻辑类和方法都不是final → 方式一继承重写最简单 ├── 类是final或只想增强部分方法 → 方式二装饰器模式 ├── 目标有接口 → 方式六动态代理 ├── 类是final 方法是final必须彻底替换 → 方式四同包同类名覆盖慎用 └── 运行时动态修改无法通过其他方式 → 方式五Java Agent ByteBuddy面试口述标准答案重写 Redis 依赖包的方法按场景有六种方式。最常用的是继承重写如果类不是 final、方法不是 final直接继承后 Override 就行。如果类是 final 或者只想增强部分方法用装饰器模式把原对象组合进来接口方法逐个委托。如果只是加日志、监控这类横切逻辑用 Spring AOP 拦截最方便无侵入。如果目标有接口可以用 JDK 动态代理没有接口用 CGLIB。极端情况下类和方法都是 final只能用同包同类名覆盖但这个是黑科技维护成本高不推荐。终极方案是 Java Agent 加 ByteBuddy 做字节码增强一般只有 APM 工具才会用。实际项目里 90% 的场景用继承或装饰器就能解决。
延伸阅读

更多相关文章

2026/10/29 7:37:38

基于SSM与微信小程序的宿舍报修系统设计与实战解析

简介:这是基于微信小程序设计的宿舍报修系统毕业源码案例,后端采用SSM架构,Java语言编码,Mysql创建数据表,面向计算机相关专业学生及小程序开发者,可用于毕业设计、课程实践或项目参考。压缩包共664个文件&…

2026/10/29 7:39:45

Codex与Claude Code同题实战:谁更胜任AI编程工程交付?

前段时间做 AI 编程工具选型时,我一直习惯用“点状测试”来比较 Codex 和 Claude Code:让 Codex 补一个函数,让 Claude Code 修一个 Bug,再手动对比一次差异。这种测试其实参考价值很有限,因为任务范围太小&#xff0c…

2026/10/22 3:11:05

整车控制器(VCU)源代码开发实战:从工程架构到量产安全

简介:整车控制器(VCU)开发源代码资料包面向新能源汽车电控开发者、嵌入式工程师及相关专业学生,涵盖VCU核心控制算法、驱动与状态机逻辑、故障处理机制及软件架构,配套软件说明书详解功能描述、编程接口与调试方法&…

2026/10/29 7:39:07

PS图层蒙版与剪贴蒙版:黑白灰原理、局部调色与排查实战

蒙版这个东西,我教过不少零基础的朋友,几乎所有人第一次听到“蒙版”两个字都是一脸懵,觉得它神秘、抽象、像是高级功能。但真上手之后你会发现,它其实是PS里最“讲道理”的一个机制:不删像素、不破坏原图、随时能反悔…

2026/10/29 7:39:07

OpenClaw智能开发工具链:模块化架构与AI协同实践

1. OpenClaw工具概述:新一代智能开发平台的利器OpenClaw作为当前开发者社区热议的智能开发工具链,其内置功能模块的设计理念源于对现代开发流程的深度重构。不同于传统IDE或CLI工具,它通过模块化架构将代码生成、环境管理、AI协同等能力封装为…

2026/10/29 7:39:07

PS图层蒙版与剪贴蒙版:从灰度原理到合成调色实战

图层蒙版和剪贴蒙版,是PS入门阶段最容易被跳过去的两个功能,也是新手做完图之后最常发出“为什么我这张图看起来像贴纸”这种疑问的根源。我见过太多人学PS的路径是先把工具栏挨个摸一遍,套索、魔棒、橡皮擦用得挺顺手,一到蒙版就…

2026/10/29 7:39:07

Procreate艺术笔刷包:30种风格笔刷参数与制作流程

做数字绘画这一行久了,最常被同行问的一句话就是“你这套笔刷哪来的”。我手上在用的这套Procreate艺术笔刷包:30种风格笔刷集合,不是从应用里一键下载的成品包,而是我按自己画稿的习惯,一支一支调出来、攒起来、再反复…

2026/10/29 7:39:07

ADE:智能体开发的基础设施重构与Control Plane实践

1. 这不是IDE的升级,而是开发范式的迁移:从写代码到编排智能体你有没有过这样的体验:在VS Code里敲完几百行Python,调试了三轮才让一个RAG流程跑通,结果发现用户真正需要的,其实只是“把PDF里的合同条款自动…

2026/10/29 7:34:06

DWVD与MCNN-BiGRU在工业故障诊断中的应用

1. 项目概述:当信号处理遇上深度学习在工业设备故障诊断领域,传统方法往往面临两个核心痛点:一是非平稳信号的特征提取困难,二是时序依赖关系的建模不足。这个项目创新性地将时频分析工具DWVD与深度学习架构MCNN-BiGRU相结合&…

2026/10/28 14:42:12

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/28 15:28:56

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/28 3:32:29

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/29 0:03:42

学生选课系统DFD图绘制指南:边界划分与分层校验实战

简介:文档以顶层与第一层DFD图为核心,完整刻画学生选课系统的逻辑模型,面向软件工程课程设计、系统分析学习及毕设前期建模人群。顶层图界定系统边界,外部实体包括管理员、教师和学生三类角色;第一层图进一步细化用户登…

2026/10/29 0:03:42

JIRA敏捷落地:Scrum角色权限、Sprint与燃尽图避坑指南

简介:围绕“基于JIRA的敏捷开发项目管理”这一主题,面向产品负责人、Scrum Master及研发测试成员,梳理Scrum角色分工、迭代流程与JIRA工具配置的对应关系,适合初、中级团队导入敏捷管理时参考。压缩包共1个docx文件,大…

2026/10/29 0:03:42

SEMI S8人机工程验收实战:从条款拆解到现场实测的完整指南

简介:面向半导体设备设计、制造与运维工程师及安全合规人员,这份资料聚焦SEMI标准体系下的设备安全规范,重点收录SEMI S8-0308《半导体制造设备人体工程学工程安全指南》。内容围绕设备设计原则、错误与事故预防、人体工程学适配三大主线展开…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑