1. Python基础专栏基础知识一网打尽9.9元买不了吃亏买不了上当。 Python从入门到精通 2. AI编程变现手册从学会AI编程到实现变现都可以 3. 毕业设计专栏毕业季咱们不慌忙几千款毕业设计等你选。❤️ 4. DeepSeekRPA提效从入门到变现实战❤️5. 欢迎访问我的免费工具站❤️ 6. Java高并发编程入门打卡学习Java高并发。 Java高并发编程入门文章目录考点全景图考点 1服务注册与发现Nacos① 原理讲透② 结合本项目怎么答③ 追问链④ 话术钩子⑤ 自测考点 2配置中心 RefreshScope 热更新 ⭐核心① 原理讲透② 结合本项目怎么答③ 追问链④ 话术钩子⑤ 自测考点 3OpenFeign 声明式调用 契约共享 ⭐核心① 原理讲透② 结合本项目怎么答③ 追问链④ 话术钩子⑤ 自测考点 4负载均衡 ⚠️含坑5诚实说明① 原理讲透② 结合本项目怎么答诚实版③ 追问链④ 话术钩子⑤ 自测考点 5服务容错 —— Feign 重试 超时 幂等 ⭐核心 ⚠️含坑1诚实说明① 原理讲透② 结合本项目怎么答诚实版③ 追问链④ 话术钩子⑤ 自测考点 6优雅停机① 原理讲透② 结合本项目怎么答③ 追问链④ 话术钩子⑤ 自测考点 7服务发现的实时性push/pull① 原理讲透② 结合本项目怎么答③ 追问链④ 话术钩子⑤ 自测考点 8微服务拆分 / 契约共享common-api① 原理讲透② 结合本项目怎么答③ 追问链④ 话术钩子⑤ 自测考点 9防超卖乐观锁① 原理讲透② 结合本项目怎么答③ 追问链④ 话术钩子⑤ 自测附录 A一分钟项目自述面试开场用附录 B诚实清单面试前必读防穿帮附录 C高频八股速记这个项目串得起来的考点全景图#考点项目载体实现状态1服务注册与发现EnableDiscoveryClient Nacos discovery✅ 完整2配置中心 RefreshScope 热更新DiscountConfig/bootstrap.yml✅ 完整3OpenFeign 声明式调用 契约共享ProductFeignClient/common-api✅ 完整4负载均衡LoadBalanced RestTemplate默认轮询⚠️ 默认轮询同集群优先未实现5服务容错Feign 重试 超时 幂等FeignConfig/ProductService.deductStock⚠️ 关重试✅、幂等内存版6优雅停机GracefulShutdownConfig✅ 完整7服务发现实时性push/pullNacosInstanceChangeListener✅ 完整8微服务拆分 / 契约共享common-api模块✅ 完整9防超卖乐观锁ProductRepository乐观锁 SQL✅ 完整考点 1服务注册与发现Nacos① 原理讲透服务启动时spring-cloud-starter-alibaba-nacos-discovery把实例信息ip、port、服务名、metadata注册到 Nacos之后靠心跳维持健康状态Nacos 2.x 用 gRPC 长连接1.x 是 HTTP 定时心跳。consumer 从 Nacos 拉取某服务的健康实例列表缓存在本地调用时按负载均衡策略选一个。Nacos 是 CP 还是 AP默认AP临时实例基于 Distro 协议保可用性短暂容忍数据不一致如果注册为持久化实例ephemeralfalse走 Raft 协议是CP。这是高频考点一定记住默认 AP、可切 CP。② 结合本项目怎么答“两个服务product-service和order-service启动类都打了EnableDiscoveryClientapplication.yml配spring.cloud.nacos.discovery.server-addr: 127.0.0.1:8848。启动后在 Nacos 控制台服务列表能看到两个服务注册上来product 我起了两个实例演示。order 通过服务名product-service发现并调用它不写死 IP。”③ 追问链QNacos 注册表数据结构→ 三层 Mapnamespace → group → serviceservice 下按 cluster 分组存实例列表。QCP 还是 AP→ 见原理层默认 AP可配 CP。Q临时实例和持久实例区别→ 临时实例靠心跳心跳停就摘除AP/Distro持久实例即使宕机也保留在注册表健康状态标记为不健康CP/Raft。Q和 Eureka / Zookeeper 比→ Eureka 纯 APZookeeper 纯 CPNacos 可切换且注册中心配置中心二合一。④ 话术钩子主动说 “Nacos 默认是 AP 的临时实例我们也可以配成持久化的 CP 实例……” → 勾出 CP/AP 深挖。⑤ 自测Nacos 默认 CP 还是 AP临时 vs 持久实例的核心区别注册表三层结构考点 2配置中心 RefreshScope 热更新 ⭐核心① 原理讲透普通单例 Bean 启动时Value注入的值就固化了Nacos 配置变了 Bean 里的字段不会自动变。RefreshScopeCGLIB 代理 懒重建把 Bean 放进自定义RefreshScope。配置变更 → 客户端收到通知 → 发布RefreshEvent→RefreshScope.refreshAll()销毁缓存里的旧目标对象 → 下次调用该 Bean 时用新配置重建。本质一句话销毁旧 Bean下次访问时用新配置重建——不是原地改字段。为什么配置放bootstrap.ymlbootstrap 上下文先于 application 上下文加载。Nacos 地址、要拉哪个 dataId 必须在应用初始化之前就知道否则Value注入时配置还没拉下来。Spring Cloud 2020 默认移除 bootstrap需引spring-cloud-starter-bootstrap启用——你项目是 2021.0.x。② 结合本项目怎么答“订单折扣率从 Nacos 动态下发。DiscountConfig打了RefreshScopeValue(\${order.discount.rate:1.0}\)注入折扣率下单时OrderService算金额 价格 × 数量 × 折扣率。在 Nacos 改order-service.yaml的order.discount.rate不重启调GET /order/config就看到新值下一笔订单立刻按新折扣算。原理是 RefreshScope 给 Bean 套 CGLIB 代理放进 refresh scope配置变更时销毁旧 Bean、下次调用用新配置重建。”③ 追问链QRefreshScope 底层→ 自定义 Scope CGLIB 代理 懒重建。Q销毁重建如果 Bean 有连接池会怎样 坑4→会出问题销毁时连接池被关、活跃连接中断。所以配置分两类业务参数折扣率、开关热更基础设施参数连接池、线程池重启生效。主动暴露这个认知 高分点。Q客户端怎么感知配置变更推还是拉→ Nacos 2.x gRPC 长连接推送为主1.x 是 HTTP 长轮询 ~30s。收到后发RefreshEvent触发刷新。QConfigurationProperties需要 RefreshScope 吗陷阱→不需要它由ConfigurationPropertiesRebinder监听EnvironmentChangeEvent自动重绑定。Value才依赖 RefreshScope。你项目OrderProperties正好是 ConfigurationProperties 方式可对比“两种我都写了”——瞬间区分于背题的人。Q多实例怎么都生效→ Nacos 广播给所有订阅该 dataId 的实例各自刷新。④ 话术钩子“热更新不是银弹有状态的 Bean 不能乱用 RefreshScope……” → 勾 Q2。“Value 和 ConfigurationProperties 的刷新机制其实不一样……” → 勾 Q4。⑤ 自测RefreshScope 原地改还是销毁重建为何连接池不能热更配置为何放 bootstrapConfigurationProperties 靠什么刷新考点 3OpenFeign 声明式调用 契约共享 ⭐核心① 原理讲透Feign 是声明式 HTTP 客户端你定义一个接口 注解Feign 用JDK 动态代理生成实现类把方法调用翻译成 HTTP 请求。调用链FeignClient接口方法 → 动态代理 →RequestTemplate组装请求 → 集成 LoadBalancer 选实例 → 编码器序列化 → HTTP 发出 → 解码器反序列化响应。底层默认用 JDKHttpURLConnection可换 OkHttp / Apache HttpClient配连接池提性能。② 结合本项目怎么答“订单服务调商品服务用 OpenFeign。我把 Feign 接口ProductFeignClient和 DTO 抽到独立的common-api模块FeignClient(name\product-service\, path\/product\)定义了getProduct(id)和deductStock(id, req)。provider商品服务和 consumer订单服务都依赖 common-api共享同一份契约避免两边接口定义漂移。下单时直接productFeignClient.getProduct(productId)像调本地方法。”③ 追问链QFeign 底层原理→ 动态代理 RequestTemplate 编解码器 集成 LoadBalancer。Q为什么把 Feign 接口抽独立模块→ 契约单一来源provider 实现该接口、consumer 引用该接口改接口两边编译期就能发现不一致缺点是模块耦合需版本管理。QFeign 和 RestTemplate 区别→ Feign 声明式接口注解可读性高RestTemplate 命令式手动拼 URL/参数。你项目两者都有Feign 调商品RestTemplateConfig里也配了LoadBalanced RestTemplate。QFeign 怎么做降级/熔断→ 配fallback或fallbackFactory需引 Sentinel/Resilience4j。你项目没做熔断降级被问到如实说这个 Demo 没接 Sentinel生产会加。④ 话术钩子主动说 “我特意把 Feign 契约抽成 common-api 共享模块就是为了 provider 和 consumer 不会各写一份 DTO 对不上……” → 展示工程思维。⑤ 自测Feign 靠什么生成实现类契约共享模块的利弊你项目做熔断降级了吗诚实答没有考点 4负载均衡 ⚠️含坑5诚实说明① 原理讲透Spring Cloud 2020 用Spring Cloud LoadBalancer取代了 RibbonRibbon 已废弃。LoadBalanced给 RestTemplate/Feign 装一个拦截器把http://service-name/xxx里的服务名替换成从注册中心选出的真实实例 ip:port。默认策略轮询RoundRobin也可换随机Random或自定义。自定义实现ReactorServiceInstanceLoadBalancer重写实例筛选逻辑。② 结合本项目怎么答诚实版“负载均衡用 Spring Cloud LoadBalancer。RestTemplateConfig里LoadBalanced修饰 RestTemplateFeign 也走它。product 起了两个实例8071/8072下单时观察返回体里的servicePort字段能看到请求在两个实例间轮询。我原本想做’同集群优先路由’——就是 consumer 优先调同机房的实例减少跨网络延迟。目前我把集群元数据打通了实例注册时带 cluster-name但自定义 LoadBalancer 的路由过滤逻辑还没落地实际还是默认轮询。这块我正在补核心是实现ReactorServiceInstanceLoadBalancer按实例 metadata 里的 cluster 和本机 cluster 匹配做优先过滤全不可用再回退全量。”⚠️红线坑5 README 原本吹已实现 ClusterPriorityLoadBalancer实际没有这个类。product 侧ClusterPriorityConfiguration只打集群元数据日志。面试务必按上面诚实版讲。③ 追问链QLoadBalancer 和 Ribbon 区别→ Ribbon 是 Netflix 旧组件已停更LoadBalancer 是 Spring 官方替代基于 Reactor更轻量。Q轮询怎么实现的→ 内部维护原子计数器position每次请求position % 实例数。Q怎么实现同集群优先/灰度路由→ 自定义ReactorServiceInstanceLoadBalancer从ServiceInstanceListSupplier拿实例列表后按 metadata 过滤。这正是你要补的讲清思路即可④ 话术钩子“负载均衡默认轮询但生产上跨机房调用延迟高理想是同集群优先——这需要自定义 LoadBalancer我正在做……” → 主动亮出知道怎么优化把未实现转成有规划。⑤ 自测LoadBalancer 取代了谁默认策略自定义同集群优先要实现哪个接口诚实你项目这块实现了吗——没有元数据打通了、路由没做考点 5服务容错 —— Feign 重试 超时 幂等 ⭐核心 ⚠️含坑1诚实说明① 原理讲透Feign 默认重试的坑Feign 有默认Retryer请求失败/超时会自动重试。危险场景扣库存接口处理慢但其实成功了Feign 超时后又发一次 →库存被扣两次。超时配置connectTimeout建连超时readTimeout读响应超时。超时时间要 下游正常处理时间否则误判。幂等同一操作执行多次和执行一次效果相同。实现手段唯一标识requestId 去重存储DB 唯一索引 / Redis SETNX / 内存 Map。② 结合本项目怎么答诚实版“我遇到过 Feign 重试导致库存超扣。根因是 Feign 默认超时会重试商品服务处理慢但实际成功重试又扣一次。解法两步一是关重试FeignConfig里Bean Retryer feignRetryer(){ return Retryer.NEVER_RETRY; }改成业务层自己控重试。同时配了Request.Options和application.yml的 connect/read timeout。二是扣减做幂等deductStock用requestId判重同一 requestId 重复请求直接返回成功不重复扣。这里我要诚实说明Demo 里幂等判重用的是进程内ConcurrentHashMap只在单实例有效多实例和重启会失效。我预留了t_deduct_record唯一索引表演示正确方向但扣减逻辑还没接进去。生产上会换成 DB 唯一索引或 Redis SETNX。”⚠️红线README 原本吹数据库唯一索引实际是内存 Map。按上面诚实版讲内存演示思路、生产换 DB/Redis反而是加分——说明你知道内存版的局限。③ 追问链Q为什么要关 Feign 重试→ 重试 非幂等接口 重复副作用超扣、重复下单。要么关重试要么接口幂等最好两者都做。Q内存 Map 幂等有什么问题→ ①多实例不共享 ②重启丢失 ③无过期清理会内存泄漏。生产用 Redis带 TTL或 DB 唯一索引靠约束冲突拦截。QDB 唯一索引怎么做幂等→ 扣减前插一条request_id唯一的记录插入成功才扣冲突DuplicateKey说明重复请求直接返回。Q重试和幂等的关系→ 重试是提高成功率的手段幂等是保证重试安全的前提。没有幂等就不能安全重试。④ 话术钩子“库存超扣这个坑表面是重试本质是非幂等接口被重复调用。我先关了 Feign 重试兜底再从根上做幂等……我 Demo 里幂等先用内存演示生产会上 DB 唯一索引……” → 主动暴露局限 诚实且有深度。⑤ 自测Feign 默认重试为什么危险关重试的代码内存 Map 幂等的三个问题DB 唯一索引怎么保证幂等考点 6优雅停机① 原理讲透问题kill -9SIGKILL直接杀进程Nacos 心跳超时前默认约 15sconsumer 还往死实例路由 → 发布时几秒请求失败。优雅停机server.shutdown: graceful让容器停止时先拒绝新请求、等存量请求处理完再关。配合主动注销JVM 关闭前主动通知 Nacos 摘除自己不等心跳超时。用killSIGTERM而非kill -9SIGTERM 才会触发 Spring 的关闭钩子。② 结合本项目怎么答“发布时出现过几秒请求失败原因是强杀进程Nacos 心跳超时前还在往死实例路由。我做了优雅停机application.yml配server.shutdown: gracefulGracefulShutdownConfig实现ApplicationListenerContextClosedEvent容器关闭时主动调NamingService.deregisterInstance()从 Nacos 注销当前实例再 sleep 等注销传播然后才真正关闭。这样发布时先摘流量再停服不丢请求。”③ 追问链Q为什么 kill -9 不行→ SIGKILL 不给进程善后机会Spring 关闭钩子不执行来不及注销。要用 SIGTERM。Q主动注销和心跳摘除的区别→ 主动注销是我告诉 Nacos 我要走了即时心跳摘除是Nacos 发现我没心跳了有延迟~15s。主动注销把这 15s 消掉。Qgraceful shutdown 等多久→spring.lifecycle.timeout-per-shutdown-phase配置最大等待时间超时强制关。QK8s 场景怎么配合→ preStop hook 先摘注册再发 SIGTERM配合 readiness 探针。④ 话术钩子“发布抖动的根因是’先停服务后摘流量’我改成’先摘流量后停服务’——ContextClosedEvent 里主动注销 Nacos……” → 讲清因果顺序。⑤ 自测kill -9 为什么丢流量主动注销 vs 心跳摘除触发优雅停机该用什么信号考点 7服务发现的实时性push/pull① 原理讲透consumer 本地缓存实例列表不是实时的。Nacos 用push pull 混合pushNacos 2.x 通过 gRPC 长连接实例变更时主动推给订阅的 consumer。pullconsumer 定时拉取兜底防推送丢失。所以新实例上线到被 consumer 感知有延迟窗口灰度/扩容时要注意。② 结合本项目怎么答“Nacos 服务发现不是实时的。我写了NacosInstanceChangeListener实现ApplicationRunner启动后用NamingService.subscribe(\product-service\, ...)订阅商品服务的实例变更。当 product 实例上下线回调里打印当前健康实例列表和变更时间。我用它观察过启动第二个 product 实例后order 端多久感知到、多久开始往新实例路由。”③ 追问链Qpush 还是 pull→ 2.x 以 gRPC push 为主pull 兜底1.x 是 HTTP 长轮询。Q新实例上线为什么不立即被调用→ 本地缓存刷新有延迟 LoadBalancer 缓存实例列表。Q1.x 和 2.x 通信区别→ 1.x HTTP 长轮询2.x 新增 gRPC 长连接性能和实时性更好。④ 话术钩子“服务发现有延迟窗口我专门写了个监听器订阅实例变更来观测这个延迟……” → 展示你不是黑盒用框架会验证机制。⑤ 自测Nacos 2.x push 还是 pull为什么新实例不被立即调用1.x/2.x 通信差异考点 8微服务拆分 / 契约共享common-api① 原理讲透微服务拆分要有清晰边界商品域、订单域各自独立服务、独立数据。契约共享Feign 接口 DTO 统一响应体抽到common-apiprovider 实现、consumer 引用单一契约来源。权衡共享模块降低接口对不上风险但引入模块耦合需版本管理改契约影响所有依赖方。② 结合本项目怎么答“我按业务域拆成商品服务和订单服务各自独立库Demo 用 H2 内存库。公共部分抽到common-apiProductFeignClientFeign 契约、DTO、统一响应体ResultTcode/message/data/timestamp、异常体系BusinessExceptionErrorCode枚举。provider 和 consumer 共享它保证契约一致、响应风格统一。”③ 追问链Q为什么统一响应体→ 所有接口返回结构一致code/message/data前端和调用方好处理全局异常处理器统一包装。Q共享模块的缺点→ 耦合。改 common-api 要重新发布所有依赖方契约膨胀会变成上帝模块。折中只放稳定契约不放业务逻辑。QDTO 和 Entity 为什么分开→ Entity 是持久层模型带 JPA 注解DTO 是传输模型解耦内部存储和对外契约避免暴露表结构。④ 话术钩子“我把 Feign 契约和 DTO 抽成 common-apiprovider/consumer 共享一份编译期就能发现接口不一致……不过共享模块要控制边界只放稳定契约不放业务逻辑否则会变上帝模块。” → 利弊都讲 成熟。⑤ 自测契约共享的利弊为什么要统一响应体DTO 和 Entity 为何分离考点 9防超卖乐观锁① 原理讲透超卖并发扣库存多个请求都读到库存充足都扣扣成负数。乐观锁不加锁靠条件更新保证。UPDATE ... SET stock stock - N WHERE id ? AND stock N靠影响行数判断成功——影响 0 行说明库存不足或被别人抢先。对比悲观锁SELECT ... FOR UPDATE加行锁串行化并发低但强一致乐观锁并发高靠重试/失败处理冲突。② 结合本项目怎么答“扣库存防超卖用乐观锁。ProductRepository里Modifying Query(\UPDATE Product p SET p.stock p.stock - :quantity WHERE p.id :id AND p.stock :quantity\)SQL 里带stock quantity条件返回影响行数。ProductService.deductStock拿到影响行数0 成功0 抛StockNotEnoughException。这样并发扣减靠数据库行级原子性保证不会扣成负数也不用SELECT FOR UPDATE悲观锁。”③ 追问链Q为什么不用SELECT FOR UPDATE→ 悲观锁串行化高并发下锁竞争严重、吞吐低。乐观锁一条 UPDATE 搞定靠 WHERE 条件 影响行数并发好。Q乐观锁失败了怎么办→ 影响 0 行时业务上返回库存不足或重试。本项目是直接抛异常。Q这个能扛超高并发吗秒杀→ 不能。DB 乐观锁单行会成热点。秒杀要 Redis 预扣减 MQ 削峰 DB 最终落库。Demo 是常规电商级别秒杀级另一套方案——诚实划清边界。Qversion 版本号乐观锁和这个区别→ version 是通用乐观锁读时取 version更新时WHERE version?并 version1这里用stockquantity是针对库存场景的特化更直接。④ 话术钩子“防超卖我用乐观锁WHERE stock quantity 影响行数判断不用悲观锁……不过这是常规电商量级真到秒杀级别得上 Redis 预扣减 MQ 削峰DB 乐观锁单行会成热点。” → 主动划清适用边界 有系统观。⑤ 自测乐观锁怎么防超卖为什么不用 SELECT FOR UPDATE这套能扛秒杀吗诚实不能version 乐观锁和 stock 条件更新的区别附录 A一分钟项目自述面试开场用“这是我做的一个 Spring Cloud Alibaba 微服务 Demo两个业务服务——商品服务和订单服务加一个共享契约模块 common-api。用 Nacos 做注册中心和配置中心OpenFeign 做服务调用Spring Cloud LoadBalancer 做负载均衡。重点不是业务多复杂而是我在里面复现并解决了几个生产级踩坑场景Feign 重试导致库存超扣、kill -9 发布丢流量、RefreshScope 热更新的 Bean 重建陷阱、乐观锁防超卖。每个坑我都有代码演示也清楚它在生产上还要怎么演进。”注意说清楚怎么演进给坑1/坑5的未实现留了诚实出口。附录 B诚实清单面试前必读防穿帮场景README 别信的旧说法真实代码面试怎么说坑1 幂等“数据库唯一索引”内存 ConcurrentHashMap“内存演示思路生产换 DB/Redis”坑5 同集群路由“ClusterPriorityLoadBalancer 已实现”该类不存在走默认轮询“元数据打通了路由逻辑正在补”熔断降级README 未提但面试常问没接 Sentinel/Resilience4j“Demo 没做生产会加”秒杀别主动吹常规乐观锁“常规电商级秒杀另一套方案”附录 C高频八股速记这个项目串得起来的Nacos CP/AP默认 AP临时实例/Distro可配 CP持久实例/Raft。配置放 bootstrap 的原因先于 application 加载要先拿到 Nacos 地址。RefreshScopeCGLIB 代理 销毁重建非原地改值有状态 Bean 慎用。Value vs ConfigurationProperties 刷新前者靠 RefreshScope后者靠 Rebinder 自动重绑。Feign 底层JDK 动态代理 RequestTemplate 编解码 LoadBalancer。LoadBalancer取代 Ribbon默认轮询原子计数器取模。Feign 重试坑默认重试 非幂等 重复副作用关重试 or 幂等。优雅停机ContextClosedEvent 主动注销 等心跳超时用 SIGTERM 不用 SIGKILL。乐观锁防超卖UPDATE…WHERE stockN影响行数判断不用 FOR UPDATE。