在实际项目中用 Redis 做分布式锁、缓存预热、接口幂等性控制几乎是 Java 后端开发绕不开的日常操作。而 Redisson 作为 Redisson 官方出品的 Java 客户端能提供分布式锁、限流器、消息队列、本地缓存等一系列高级能力很多团队都选择了它却在集成方式上纠结过到底是直接引入redisson原始依赖、手工配置RedissonClient还是走 Spring Boot Starter 的自动配置这两条路线我都完整走过一遍这篇就把两套流程从头到尾掰开讲清楚包括项目里的配置代码、YAML 写法、Bean 初始化细节、实测下来的坑尽量让初次接手的开发者照着文档也能搞定不再踩我当年踩过的坑。Redisson 的集成难点不在 API而在 Spring 容器管理、配置源绑定、版本匹配这几块的取舍。原始依赖方式灵活、轻量适合你希望完全掌控客户端生命周期、不依赖自动配置魔法的场景Starter 方式封装度高、配置量小适合走 Spring Boot 习惯路线、想快速接入并依赖官方默认约定的项目。下面我按项目实际落地的顺序来写从依赖、配置、Bean、使用到验证一条龙走完再补一个避坑清单。1. 项目整体设计与两种集成路线的选择1.1 核心需求梳理为什么需要 Redisson先说清楚我们为什么引入 Redisson而不只是用RedisTemplate或者直接操作 Jedis/Lettuce。在项目里Redis 作为分布式缓存和数据共享存储本身可以解决很多问题。但一旦涉及分布式场景下的并发控制比如秒杀减库存、订单创建幂等、定时任务多实例互斥就需要一个可靠的分布式锁。原生 API 手工SETNX加锁、lua脚本解锁虽然也能实现但有很多细节需要自己维护锁自动续期、锁超时、可重入、公平锁、红锁等。Redisson 把这一整套封装成了开箱即用的RLock还顺带提供了RMap、RAtomicLong、RCountDownLatch、分布式限流RRateLimiter等高级结构省下的开发时间相当可观。除此之外Redisson 自身实现了一个高效且具备本地缓存能力的RLocalCachedMap可以在 Redis 和本地内存之间做两级缓存同步。对于热点数据频繁读取的场景这个能力对降低 Redis 负载有立竿见影的效果。所以项目引入 Redisson往往是冲着分布式锁和缓存加速这两大核心能力去的。1.2 两套方案对比原始依赖与 Spring Boot Starter我开始集成时走得是 原始依赖 路线在pom.xml中只加入redisson的坐标然后用Config类手动创建RedissonClient实例并把这个实例以Bean的形式注册到 Spring 容器。好处是依赖只有一个配置逻辑完全掌握在自己手里不依赖 Spring Boot 自动配置机制适合项目对依赖精简、启动过程可控性要求高的场景。坏处也很明显所有配置项都要手写代码映射配置文件中配置类属性需要手工绑定稍微不够Spring Boot 化。后来在另一个微服务项目里我换成了redisson-spring-boot-starter自动配置方式。只需要在pom.xml中引入官方 Starter再在application.yml中写 Redis 的地址、密码等配置项Spring Boot 就会自动创建RedissonClientBean。这个方式的配置非常简洁约定大于配置对团队协作也更友好。不过它也引入了一个隐患——如果版本与 Spring Boot 主版本匹配不当容易出现自动配置不生效或者客户端初始化失败的问题。下面先看原始依赖路线怎么走通。2. 原始依赖集成方式手动配置才是彻底理解底层的捷径2.1 引入原始依赖需要注意的坐标和版本原始依赖集成第一步当然是加入 Maven 坐标。注意 Redisson 的 groupId 是org.redissonartifactId 是redisson。这里容易踩的第一个坑是版本选择我在早期项目里随手引入了一个较新的3.x版本结果与项目里的 Netty 版本冲突导致启动时一堆NoSuchMethodError。建议不要手动指定太随意的版本最好在 Spring Boot 项目的properties中显式声明版本并且优先选用与当前 Spring Boot 大版本兼容的官方 Release 版本。Redisson 的 GitHub 仓库会发布针对不同 Spring Boot 版本的适配版本你可以在仓库的 Issue 或 Release Notes 中看到推荐版本号。合理做法是在依赖配置中声明如下properties java.version17/java.version spring-boot.version3.2.5/spring-boot.version redisson.version3.27.2/redisson.version /properties dependency groupIdorg.redisson/groupId artifactIdredisson/artifactId version${redisson.version}/version /dependency如果项目已经通过 Spring Boot 父 POM 引入了spring-boot-dependenciesRedisson 并非其托管依赖所以必须显式写版本号。我见过不少同事在复制粘贴后忘了版本号导致 Maven 直接强制版本为RELEASE的情况编译虽然能过但启动时一堆奇奇怪怪的兼容问题排查起来很费时间。2.2 配置核心对象 RedissonClient单机、集群与 Sentinel 方式在原始依赖模式下RedissonClient的初始化是通过org.redisson.config.Config对象完成的。这也是两条集成路线中我强烈建议开发者至少手写一遍的地方因为你对底层连接方式的理解会深很多。单机模式的配置示例Configuration public class RedissonConfig { Value(${spring.redis.host:127.0.0.1}) private String redisHost; Value(${spring.redis.port:6379}) private int redisPort; Value(${spring.redis.password:}) private String redisPassword; Bean(destroyMethod shutdown) public RedissonClient redissonClient() { Config config new Config(); config.useSingleServer() .setAddress(redis:// redisHost : redisPort) .setPassword(redisPassword.isEmpty() ? null : redisPassword) .setConnectionMinimumIdleSize(10) .setConnectionPoolSize(50) .setIdleConnectionTimeout(60000) .setConnectTimeout(10000) .setTimeout(3000) .setRetryAttempts(3) .setRetryInterval(1500) .setDatabase(0); return Redisson.create(config); } }注意这里destroyMethod shutdown很关键。RedissonClient并不是 Spring 标准生命周期组件如果不在 Bean 销毁时调用shutdown()应用关闭时 Netty 线程池不会优雅释放在频繁重启的测试环境容易造成连接泄漏。我见过一个同事因为漏写这个属性在本地重启了三十多次之后 Redis 连接数暴涨被 DBA 直接发了警告邮件。集群模式也很常见配置方式变成了useClusterServers()Bean(destroyMethod shutdown) public RedissonClient redissonClientCluster() { Config config new Config(); config.useClusterServers() .addNodeAddress(redis://192.168.1.101:6379, redis://192.168.1.102:6379) .setScanInterval(2000) .setMasterConnectionMinimumIdleSize(10) .setMasterConnectionPoolSize(50) .setSlaveConnectionMinimumIdleSize(10) .setSlaveConnectionPoolSize(50); return Redisson.create(config); }集群模式下scanInterval是节点变动感知间隔如果集群节点扩容或故障转移客户端能更及时发现。这套手动配置模式的好处是每个参数都在代码里显式可见出错时可以直接定位坏处是配置文件中的连接参数无法自动绑定我上面的写法通过Value注入是一种折中做法比硬编码好维护多了。2.3 编写一个可直接注入使用的工具类或封装Service光有RedissonClient还不够通常还需要封装一层 Service避免业务代码直接散落一堆getLock()、unlock()的样板代码。我的做法比较简单Service public class DistributedLockService { private final RedissonClient redissonClient; public DistributedLockService(RedissonClient redissonClient) { this.redissonClient redissonClient; } public T T executeWithLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit, SupplierT supplier) { RLock lock redissonClient.getLock(lockKey); boolean locked false; try { locked lock.tryLock(waitTime, leaseTime, unit); if (!locked) { throw new RuntimeException(获取分布式锁超时, key lockKey); } return supplier.get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(线程中断获取锁失败, e); } finally { if (locked) { lock.unlock(); } } } }为什么要封装成SupplierT形式因为锁的目的是保护一段资源操作拿到锁之后执行的逻辑往往是动态的。封装成函数式接口后业务侧代码只需要一行调用就能完成加锁、执行、解锁全流程代码变得清爽。同时把锁的 key 设计、超时时间划分收敛到集中的工具类里后续调整waitTime、leaseTime时不用满项目找。关于leaseTime要注意如果传了leaseTimeRedisson 不会自动开启看门狗续期机制锁在指定时间后会自动释放如果不传leaseTime使用tryLock(waitTime, timeUnit)重载Redisson 默认开启看门狗续期默认锁过期时间是 30 秒每 10 秒自动续期一次。这个选择要结合业务场景如果明确知道业务执行时间不会超过某个阈值传leaseTime是安全的如果是未知耗时的长任务建议不传leaseTime靠看门狗续期。2.4 原始集成方式的适用边界与取舍原始依赖集成方式并不是银弹它的适用边界主要在于对第三方组件初始化有强控制要求的项目或者不想让 Spring Boot 自动配置参与太多隐式魔法的场景。比如你手头项目里已经有一个自己的 Redis 连接工厂类的私有封装或者你依赖的 Redisson 版本是内部定制的二次开发包这种场景下 Starter 自动配置反而碍事手动 Bean 方式才是正解。不过一旦项目里有多个RedissonClient实例比如连接多个 Redis 集群手动方式的可读性就会快速下降因为你不得不在配置类里为每个实例编写ConfigurationProperties绑定类或复制粘贴一堆Value。这个时候 Spring Boot 的自动配置机制 Properties类绑定的优势就很明显了。下一个章节展开 Starter 集成方式。3. Spring Boot Starter 集成方式自动化配置的核心流程3.1 引入 Starter 依赖关注版本矩阵Starter 集成的第一步是替换依赖把org.redisson:redisson换成org.redisson:redisson-spring-boot-starter。坐标如下dependency groupIdorg.redisson/groupId artifactIdredisson-spring-boot-starter/artifactId version${redisson.version}/version /dependency这个 Starter 与传统依赖共存会有冲突风险。如果同时引入了redisson和redisson-spring-boot-starter会自动触发两套初始化路径极易产生RedissonClientBean 重复或 Netty 线程池资源浪费排查起来云里雾里。所以用 Starter 时记得移除手动redisson依赖。版本匹配是 Starter 集成最需要认真对待的事情。Redisson 官方在发布时会对齐 Spring Boot 版本比如面向 Spring Boot 2.x 的 starter 与面向 3.x 的 starter 是有差异的。看一眼redisson-spring-boot-starter的 POM 就会发现它内部传递引入了org.redisson:redisson-spring-boot-autoconfigure这个模块又区分javax与jakarta两种命名空间分别对应 Spring Boot 2.x 和 3.x。简单说Spring Boot 3.x 项目必须选择 Redisson 3.20 且确认 autoconfigure 模块用的是jakarta否则启动时会报ClassNotFoundException: javax.annotation.Resource之类的错误。我建议在项目初始化时就统一整理一张版本清单明确 Spring Boot、JDK、Redisson 三者的对应关系防止后续升级时踩坑。3.2 application.yml 配置项详解引入 Starter 后配置工作大幅简化。核心配置只需要在application.yml中按官方 schema 编写spring: data: redis: host: 127.0.0.1 port: 6379 password: database: 0 redisson: config: | singleServerConfig: address: redis://127.0.0.1:6379 password: null connectionMinimumIdleSize: 10 connectionPoolSize: 64 timeout: 3000 connectTimeout: 10000 retryAttempts: 3这里有一个重大变化值得注意从 Spring Boot 2.x 到 3.x官方 Redis 的配置前缀从spring.redis变更为spring.data.redis而 Redisson 的配置前缀是spring.redisson。不少迁移项目在升级 Boot 3.x 时只改了spring.redis→spring.data.redis却忘了检查spring.redisson的配置结构导致 RedissonClient 静默回退到本地默认地址127.0.0.1:6379连不上远程 Redis 才发现问题。Starter 支持两种配置风格一种是上面这种通过config直接内联一段 YAML 字符串另一种是使用spring.redisson.file-config指定一份外部 Redisson 配置文件。我更推荐内联config方式因为所有配置都在主配置文件中环境隔离时只需要区分不同 profile 的 YAML 即可不用额外维护 redisson 独立配置文件的打包问题。3.3 Starter 自动装配机制解读RedissonAutoConfiguration 干了什么很多人把 Starter 当作黑盒用完就忘。但在排查问题时不懂自动装配机制会非常吃亏。简单拆解一下RedissonAutoConfiguration的工作过程。Starter 通过spring.factoriesBoot 2.x或AutoConfiguration.importsBoot 3.x注册自动配置类。自动配置类核心逻辑是读取spring.redisson下的配置属性如果找不到则检查spring.data.redis或spring.redis下的配置构造Config对象调用Redisson.create(config)创建RedissonClient同时注册RedissonTemplate、RedissonRxClient、RedissonReactiveClient等可选扩展 Bean。关键细节在于自动配置类使用了ConditionalOnMissingBean、ConditionalOnClass这类条件注解也就是说如果你自己已经定义了一个RedissonClientBean自动配置会直接让位不会重复创建。这种方式很灵巧但也会带来一个隐蔽问题——调试时如果你觉得 Starter 配置没生效可能不是它没生效而是你的自定义 Bean 把自动配置屏蔽了。3.4 Starter 集成的典型使用代码Starter 集成后业务代码与原始依赖方式几乎没有差别因为最终拿到的都是RedissonClient。例如RestController RequestMapping(/demo) public class DemoController { private final RedissonClient redissonClient; public DemoController(RedissonClient redissonClient) { this.redissonClient redissonClient; } GetMapping(/lock) public String lockDemo() { RLock lock redissonClient.getLock(demoLockKey); boolean locked false; try { locked lock.tryLock(3, 10, TimeUnit.SECONDS); if (!locked) { return 未获取到锁; } // 模拟业务 Thread.sleep(2000); return 成功执行业务逻辑; } catch (InterruptedException e) { Thread.currentThread().interrupt(); return 执行中断; } finally { if (locked lock.isHeldByCurrentThread()) { lock.unlock(); } } } }这段代码里lock.isHeldByCurrentThread()是最后一道保险。在可重入锁场景下同一线程多次lock()需要在finally中判断当前线程确实持有锁再释放否则可能把别人的锁误删。Redisson 底层解锁是通过 Lua 脚本校验线程标识的直接unlock不会误删别人的锁但会在当前线程未持锁时抛IllegalMonitorStateException因此这个判断能保证不出现异常堆栈。3.5 Starter 集成方式的核心优势Starter 最大的优势是把配置与 Spring 环境绑定配置文件即代码。spring.redisson.config内联配置能利用 Spring Boot 的ConfigurationProperties机制做配置源绑定配合RefreshScope、Nacos 配置中心可以动态刷新连接配置——这是原生依赖方式需要额外开发工作量才能实现的。另外Starter 还自动注册了RedissonTemplate封装了常用操作Autowired private RedissonTemplate redissonTemplate;它可以简化 Redis 的 key/value 存取操作内部已经做了序列化处理比直接用RedissonClient.getBucket()方便一些。不过我这里要提醒一句RedissonTemplate的 API 覆盖范围远不如原生客户端全面如果你的业务流程大量使用RMap、RQueue、RTopic等高级结构直接用RedissonClient更顺手。4. 两条路线对比选择依据与项目实战取舍4.1 核心差异对照表为了让你在架构评审时能拿出有说服力的材料我整理了一张对照表从多个角度对比两条路线对比维度原始依赖redissonSpring Boot Starter依赖数量仅一个核心包Starter autoconfigure配置方式Java Config 手动创建 BeanYAML 声明式绑定自动配置不使用完全手动自动装配条件注解控制版本管理自行管理需手动查兼容性依赖内部 POM 管理一部分传递依赖配置中心支持需自研属性刷新逻辑天然支持配置源与环境绑定多数据源支持可定义多个 Bean但代码量大自动配置只创建一个 Bean多数据源需绕行学习成本需理解 Config API需理解自动装配与版本矩阵启动可控性完全可控启动过程透明自动装入部分行为有隐藏逻辑适合场景定制需求多、二次开发、内部统一封装标准单集群、快速接入、规范团队协作从我的项目经验看如果团队有多个服务共享一个自定义的 Redis 初始化工具包原始依赖方式更适合做统一收敛如果是常规微服务Starter 方式写起来最舒服也更容易让新成员接手。4.2 混合使用与迁移策略在实际维护中我也见过不少项目走了一个混合路径保留 Starter 依赖但通过自定义Configuration里的Bean方法手动覆盖RedissonClient。这样既能享受 Starter 带来的配置绑定便利又能对客户端进行二次定制比如加入自定义NettyHook、自定义Codec、统一的连接监听器。实现方式很简单——在Configuration类中自己声明 Bean由于自动配置类有ConditionalOnMissingBean你的自定义 Bean 会优先生效。如果你现在还在使用原始依赖方式想要平滑迁移到 Starter我建议按这种顺序操作先在项目中引入 Starter 依赖同时保留原始redisson依赖但把Config的Bean方法注释掉观察启动日志确认自动配置是否正确创建了 Bean验证自动配置创建的客户端能正常加锁解锁删除自定义Bean方法及Config类把所有参数迁移到 YAML跑两轮集成测试重点检查 Redis 连接池、锁的公平性、看门狗续期行为。迁移后还要留意一个细节Starter 方式在默认情况下使用的Codec是Kryo5Codec一些旧版是MarshallingCodec而手动配置时很多人习惯用JsonJacksonCodec。这会导致 Redis 中已有缓存数据反序列化时类型不对应报错或者读出 null。遇到这种情况直接在 YAML 中指定 codec 即可spring: redisson: config: | codec: !org.redisson.codec.JsonJacksonCodec {}这个语法是 YAML 的标签类型表示法用来在 Redisson Config 反序列化时指定具体类。第一次写时很容易漏掉!...格式直接写JsonJacksonCodec字符串读取配置时会报类型转换错误。4.3 真实项目中的选型倾向从我接触到的多个中大型后端项目来看绝大多数标准 Spring Boot 服务最终都落到了 Starter 方式上。原因很现实团队协作中配置维护成本最低接入监控、修改参数都可以通过配置中心热更新不用频繁发版。但如果你维护的是底层公共组件或公司级中间件原始依赖方式更合适——Starter 自动装配的黑盒特性会让下游使用者的异常排查路径变长不利于快速定位问题。有一次我在公司内部做组件升级时就是因为某个基础库从原始依赖切换成 Starter结果下游十几个服务的启动时间变长了一点排查下来发现是 Starter 自动配置加载了本地缓存、事件总线等额外组件导致初始化时多了许多无用的 Bean 创建。这类隐式开销在原始依赖方式下是完全不会出现的。5. 核心实操经验常见问题、踩坑记录与排查技巧5.1 版本匹配问题ClassNotFoundException 与 NoSuchMethodError我在不同项目里遇到最多的两类问题一是javax与jakarta命名空间冲突二是Netty版本冲突。javax问题通常出现在 Spring Boot 3.x 项目配了旧版 Redisson Starter 时。报错信息很直白java.lang.ClassNotFoundException: javax.annotation.Resource但其实真正的原因可能是 Starter 内部引入了javax.annotation-api或者spring-boot-starter-web中的旧传递依赖。快速解法是升级 Redisson 到 3.25并确认redisson-spring-boot-starter依赖的redisson-spring-boot-autoconfigure中pom.xml的依赖是jakarta.servlet-api而不是javax.servlet-api。不放心的话在 IDE 中直接搜索项目的依赖树过滤javax.annotation相关的包即可。Netty 版本冲突的表现则是编译通过、运行时NoSuchMethodError。由于 Spring Boot 3.x 内置的 Netty 版本与 Redisson 内部要求的 Netty 版本可能不同我建议在 POM 中直接使用 Redisson 传递过来的 Netty 版本为主或者显式指定一个同时兼容双方的版本。遇到这个报错时别慌在 Maven 依赖树中筛出所有io.netty:netty-*依赖检查版本号是否统一再决定是exclusion还是dependencyManagement强制定版。这两种方式我都在不同项目里验证过后者更稳定避免重复引包。5.2 序列化导致的数据错乱Redisson 的默认序列化策略在不同版本中不同如果你往 Redis 中写入了一堆缓存数据后升级了 Redisson 版本很可能发现数据读取不了。这个问题的根因是Codec的变化。例如手动配置方式默认Codec是JsonJacksonCodec而 Starter 自动配置模式下可能是Kryo5Codec。这两种编解码器对同一个对象的序列化结果完全不同。所以重要数据写入时最好在全局配置里指定Codec并且在升级 Redisson 前分别读取和验证 Redis 中现有数据。我的建议是spring: redisson: config: | codec: !org.redisson.codec.Kryo5Codec {}或者如果团队普遍对 JSON 更熟悉codec: !org.redisson.codec.JsonJacksonCodec {}但注意JsonJacksonCodec序列化后的对象在 Redis 中不带类名元数据反序列化时依赖Class?推断所以RMap读取时如果值对象类型是接口或父类有可能反序列化错误。这种情况下使用TypedJsonJacksonCodec能减少问题。5.3 看门狗续期锁为什么没有在预期时间释放Redisson 官方宣传的看门狗机制很美好但也坑过不少人。看门狗生效的前提是在获取锁时没有指定leaseTime。如果业务代码里调用了lock.tryLock(3, 30, TimeUnit.SECONDS)那么看门狗不会启动锁在 30 秒后必然释放。注意如果业务执行时间超过了leaseTime其他线程就会拿到锁产生并发冲突。我踩过的一个实际案例是一个定时任务在集群部署下需要互斥执行我一开始用了tryLock(10, 30, TimeUnit.SECONDS)看似稳妥结果某个批次数据量暴增任务实际跑了 40 多秒另一个节点在第 30 秒时成功拿到了锁同一批数据被处理了两遍。后来改为不传leaseTime只传waitTime让看门狗自动续期问题才解决。所以我的经验是如果业务执行时长不确定优先使用tryLock(waitTime, TimeUnit.SECONDS)让 Redisson 自动续期。并且要理解看门狗的续期原理——Redisson 在获取锁后会定时向 Redis 发送 Lua 续期指令但客户端长时间阻塞或 GC 停顿可能导致续期不及时锁提前释放。因此核心业务中锁内操作要避免长时间网络 IO、避免大对象 GC 停顿。5.4 连接池参数设置不当导致锁获取超时在压测阶段我发现锁获取超时比例很高但 Redis 本身压力并不大最后定位是connectionPoolSize设置过小。当并发量大时多个线程同时竞争调用 tryLock连接池被占满队列中等待的请求排队太久看起来就像获取锁超时。合理设置连接池的思路是结合应用的单机 QPS、平均锁持有时间、Redis 实例规格推算。假设平均锁持有时间 200ms单机对锁操作的 QPS 是 500那么理论上需要的并发连接数为500 * 0.2 100而 Redisson 默认connectionPoolSize是 64此时可能不够。因此在压测后我会把connectionMinimumIdleSize默认 10和connectionPoolSize默认 64都调大一些比如前者 32、后者 128。也要防止过大连接数太多会占用 Redis 端连接文件描述符反而拖垮性能。5.5 在 Spring AOP / 事务中使用的注意事项Redisson 的锁操作与 Spring 事务是两套机制没有自动协同。如果在Transactional方法内使用 Redisson 锁要注意锁的释放是在业务方法退出后但事务可能还要等到数据库提交完成才真正结束。这个窗口期内其他线程可能已经拿到锁读到旧数据。要规避这个场景我一般建议把锁的范围放大到事务方法之外或者使用编程式事务确保锁的释放发生在事务提交之后。另外一个细节是RLock的锁粒度默认是进程内可重入如果你在一个请求中多次调用getLock获取同一个 key 的锁Redisson 会维护同一客户端下的加锁计数。但如果锁内发起了异步线程且异步线程也去获取同一个锁它会因为缺少线程标识而拿不到锁表现就是异步线程死等或者获取锁失败。这类跨线程加锁问题官方没有直接 API 支持我用RCountDownLatch或者其他信号量结构绕过。5.6 主从切换与锁安全RedLock 的必要性分析还有一个团队经常讨论的话题主从模式下如果 Redis master 挂掉锁怎么办。默认情况下Redisson 的分布式锁不保证强一致master 保存着锁数据如果 master 宕机且数据未同步到 slave锁就丢了其他客户端可能同时获得锁。在资金类、库存类等强一致场景下可以启用 Redisson 的多节点 RedLock 方案但 RedLock 本身有争议且对 Redis 部署有额外要求。我的看法是对于大多数非资金类的互联网业务单集群足够的可靠性已经能接受了没必要为了极端场景付出高成本但如果业务对一致性要求极高就要架构层面单独评估而不是简单套个 RedLock 就当万事大吉。5.7 常见问题速查表下面这张表是我在实际项目中养成的排查习惯遇到问题先对照一遍现象描述最可能原因解决方向启动时ClassNotFoundException: javax.annotation.ResourceRedisson 版本与 Spring Boot 3.x 不匹配升级 Redisson确认 autoconfigure 使用 jakarta运行时报NoSuchMethodErrorNetty 传递依赖冲突排查依赖树统一 Netty 版本RedissonClient 连不上远程 Redisspring.redisson配置前缀不对或未配置确认spring.redisson.config配置块内容锁提前释放导致并发问题指定了leaseTime看门狗未启动改用不传leaseTime的方式缓存数据读取出错Codec 不匹配统一指定 codec或清缓存后重新加载锁获取超时频频连接池连接数过小增大connectionPoolSize控制锁内耗时自动配置不生效自定义RedissonClientBean 存在移除自定义 Bean 让自动配置生效锁丢失主从切换未同步评估 RedLock 或多方案组合6. 一些个人实战心得在 Spring Boot 项目里集成 Redisson本质是处理一个第三方客户端与 IoC 容器之间的配合关系。原始依赖方式让我把Config、RedissonClient、RLock这些底层概念理解透了Starter 方式则让我体会到自动配置在标准场景下的高效率。如果你现在正卡在为什么我这样配不行的问题上我建议先把自动配置逻辑关闭手写一遍原始依赖往往能更快发现真正的问题点。我再分享一个常用的小技巧在本地测试时经常需要验证锁是否真的生效。可以启动两个 Spring Boot 实例修改端口然后用同一个 key 并发触发接口观察是否只有一个实例能进入临界区。如果两个实例都进入了十有八九是实例之间用了不同的 Redis database或者配置文件的连接地址写成了localhost导致连接的不是同一个 Redis。这个验证方式虽然土但比单测可靠得多。另外如果是重构现有项目接口的幂等性控制、缓存延时双删这些场景也都可以顺势用 Redisson 简化。比如延迟双删可以改用RTopic的发布订阅机制让所有节点同时收到删除缓存的指令比轮询数据库变更表的方式优雅不少。Redisson 集成工作做完之后项目的分布式基础设施也算是补齐了一块重要拼图。