Spring3到SpringBoot迁移的关键问题与改造路径

1. 对应简历段落

这篇文章对应简历中“遗留系统架构升级、保险业务核心系统现代化改造、从传统单体应用迁移到 Spring Boot 微服务体系”的项目经历。可以在简历中表述为:

参与公司核心业务系统现代化改造,负责将 Ant 构建的 Spring3 + MyBatis + WebLogic 遗留应用逐步迁移为 Maven + Spring Boot + Undertow 的服务化架构;改造过程中完成 MyBatis 兼容适配、配置中心接入、服务注册发现、统一网关、ELK 日志链路、定时任务平台化等能力建设,支撑保险销售、订单流转、客户服务、运营管理等业务模块平稳迁移。

这个段落真正想表达的不是“我会 Spring Boot”,而是“我能把一个多年运行、技术栈陈旧、依赖复杂、业务风险高的系统,拆解为可控的迁移工程”。面试官通常不会只问 Spring Boot 自动配置原理,还会追问:为什么要迁移?迁移过程中哪些地方最危险?老系统和新系统如何并行?WebLogic 和 Undertow 行为差异怎么处理?MyBatis 老 XML 怎么兼容?配置、日志、任务和网关如何治理?上线失败如何回滚?

因此,这类项目要讲成一条完整的改造链路:从构建体系开始,解决可编译、可依赖、可打包;再解决框架升级,解决 Bean、事务、MVC、配置加载差异;然后解决运行容器差异,处理 JNDI、ClassLoader、Session、编码、线程池;最后补上分布式运行能力,包括 Nacos、Gateway、ELK、XXL-Job、灰度发布和回滚机制。

2. 业务背景

遗留系统通常不是因为“代码丑”才迁移,而是因为它已经影响业务迭代效率、稳定性和运维成本。以保险销售和客户运营系统为例,老系统最初可能是一个部署在 WebLogic 上的传统 WAR 包,业务覆盖代理人管理、客户资料、产品配置、保单试算、订单提交、回访工单、运营报表等模块。早期系统采用 Spring3、Spring MVC、MyBatis、Oracle、Quartz、Log4j,构建方式使用 Ant 脚本,依赖 jar 包放在 lib 目录,环境配置通过 properties、XML 或 WebLogic 控制台维护。

这种架构在业务规模较小时能够稳定运行,但随着线上渠道增加、营销活动频繁、移动端和内部运营平台不断接入,问题会逐渐暴露。第一,交付效率低。Ant 构建脚本缺少标准依赖管理,jar 包版本靠人工维护,不同开发环境和测试环境经常出现“我本地能跑、测试环境缺类”的问题。第二,部署复杂。WebLogic 启停慢,单个 WAR 包变大后发布窗口长,一次小改动也可能需要完整重启。第三,配置分散。不同环境的数据库、缓存、外部接口、任务开关散落在服务器目录和控制台里,缺少集中审计。第四,日志不可观测。出现客户投保失败、订单状态不一致、接口超时等问题时,只能登录机器翻日志,缺少 traceId、调用链和统一检索。第五,任务不可控。Quartz 任务随应用部署,集群环境下需要处理锁和重复执行,任务失败重试、手动触发、执行历史都不友好。

业务侧的诉求也很明确:核心交易不能中断,已有接口不能大面积改动,数据一致性不能破坏;同时,新业务希望更快上线,服务能够水平扩容,日志能够快速定位,任务能够统一调度,配置能够动态发布。也就是说,这不是一次“技术升级秀”,而是一次在业务连续性约束下完成的工程治理。

3. 迁移难点

Spring3 到 Spring Boot 的迁移难点不在于创建一个新工程,而在于旧系统背后存在大量隐性契约。

第一类难点是依赖和构建不可控。Ant 项目常见做法是手工维护 WEB-INF/lib,很多 jar 没有明确版本来源。有些 jar 是厂商包,有些是公司内部二方包,有些是被手动改过的补丁包。迁移到 Maven 后,必须梳理每个依赖的 groupId、artifactId、version、作用域和传递依赖。如果只是把 jar 粗暴放进本地仓库,后续仍然无法治理。更麻烦的是,老项目可能依赖同一个库的多个版本,例如 commons-lang、jackson、dom4j、cglib、asm、mybatis、spring-aop 等,WebLogic 自身也会提供一部分库,迁移到内嵌容器后类加载顺序变化,原来被容器“兜底”的类冲突会暴露出来。

第二类难点是 Spring 容器行为变化。Spring3 时代大量配置写在 XML 中,Bean 命名、扫描路径、事务切面、拦截器、PropertyPlaceholderConfigurer、FactoryBean、自定义 Namespace 都可能有历史包袱。迁移到 Spring Boot 后,自动配置会引入一批默认 Bean,例如 DataSource、TransactionManager、ObjectMapper、MessageConverter、MultipartResolver、Validator、ErrorController 等,如果不加控制,可能和老系统 Bean 冲突。老系统里一些依赖初始化顺序的代码,也可能因为 Boot 的自动配置和条件装配变得不稳定。

第三类难点是 WebLogic 到 Undertow 的容器差异。WebLogic 是完整 Java EE 容器,内置 JNDI、连接池、事务、JMS、安全域、部署描述符和较复杂的 ClassLoader 体系。Undertow 是轻量级内嵌 Servlet 容器,它更适合 Spring Boot 打成可执行 jar,但不再提供 WebLogic 那套企业容器能力。老系统如果通过 JNDI 获取数据源、使用 WebLogic 特定部署描述符、依赖容器级 Session 复制、使用服务器编码配置或线程池配置,迁移后都要显式改造。

第四类难点是 MyBatis 兼容。老系统 XML 中可能存在大量动态 SQL、数据库方言写法、ResultMap 继承、存储过程调用、批量插入、分页插件、自定义 TypeHandler、拦截器和二级缓存配置。Spring Boot 接入 MyBatis Starter 后,SqlSessionFactory、Mapper 扫描、事务管理、插件顺序、类型别名包扫描都可能和旧系统不一致。只要一个 Mapper XML 没被加载,或者分页插件顺序变化,就可能造成生产查询结果异常。

第五类难点是周边能力迁移。Nacos 引入后,配置从本地文件转向配置中心,必须考虑启动期配置、动态刷新、敏感信息和多环境隔离。ELK 接入后,需要统一日志格式和 traceId 传递,否则只是把分散日志搬到了 Elasticsearch。Gateway 接入后,要处理路径改写、鉴权、限流、跨域、超时和老接口兼容。Quartz 到 XXL-Job 迁移后,要保证任务不重复、不漏跑、可补偿,还要考虑老任务在迁移窗口内是否同时存在。

4. 迁移路线

稳妥的迁移路线应该分阶段推进,而不是一次性重写。核心原则是:先把系统“标准化”,再把运行时“轻量化”,最后把能力“平台化”。

第一阶段是资产盘点。先盘点模块、接口、数据库表、定时任务、外部依赖、批处理脚本、文件目录、WebLogic 配置、环境变量、证书、消息队列、缓存、第三方接口和生产调用量。这个阶段要产出一份迁移清单,把每个功能按风险分级:核心交易链路、查询类接口、运营后台、报表批处理、低频管理功能。保险系统里,投保、支付、核保、订单状态回写属于高风险,客户标签查询、产品列表、运营配置属于中低风险。

第二阶段是 Ant 到 Maven。目标不是先升级框架,而是让项目可以被标准化构建。可以先保留原有 Spring3 和 WAR 部署方式,只把依赖、资源、编译、测试、打包迁移到 Maven。做法包括:建立父 POM 管理版本;将原 lib 目录依赖逐个 Maven 化;无法从公共仓库获取的厂商包进入公司 Nexus 私服;区分 compile、provided、runtime、test 作用域;把不同环境配置从源码中剥离;用 Maven profile 管理构建差异。这个阶段完成后,至少要保证 Maven 打出的 WAR 和 Ant 打出的 WAR 在文件结构、依赖列表和功能行为上可对比。

第三阶段是 Spring3 到 Spring Boot 兼容启动。不要一上来删 XML。更现实的方式是先搭建 Boot 主类,通过 @ImportResource 引入原有 Spring XML,让老 Bean 仍然按原方式创建;再逐步把数据源、事务、MVC、拦截器、静态资源、异常处理、配置加载迁移到 Boot 风格。这样做的好处是迁移粒度可控,旧系统 Bean 不需要一次性全部改注解。等应用可以在本地通过 Boot 启动后,再处理自动配置冲突和包扫描边界。

第四阶段是 WebLogic 到 Undertow。这个阶段将部署形态从外置容器 WAR 迁移为可执行 jar,容器能力下沉到应用配置中。JNDI 数据源改为 HikariCP 或公司统一连接池配置,WebLogic 部署描述符中的上下文路径、编码、Session、错误页、资源映射要迁移到 Spring Boot 配置或代码中。对于原来依赖 WebLogic 控制台维护的线程池、连接池、证书和安全配置,要在新体系中找到对应位置,避免“上线后才发现配置没人知道在哪里”。

第五阶段是服务化和平台化。将应用接入 Nacos 注册中心和配置中心,通过 Gateway 暴露统一入口,通过 ELK 建立日志检索,通过 XXL-Job 管理定时任务。这里要注意顺序:先保证应用以 Boot + Undertow 稳定运行,再接入注册发现;先统一日志格式和 traceId,再接入 ELK;先梳理任务幂等和执行窗口,再迁移到 XXL-Job。否则平台能力会掩盖基础问题,排查会更困难。

第六阶段是灰度和拆分。对于大单体系统,不建议一次拆成多个服务。可以先按业务边界做“模块内服务化”,例如把产品配置、客户画像、订单查询、任务处理等低耦合能力拆出,核心交易链路暂时保留。Gateway 通过路由规则把部分流量导到新服务,老系统作为兜底。等日志、监控、回滚和数据对账成熟后,再逐步扩大范围。

5. 配置与依赖治理

配置治理是迁移中最容易被低估的部分。老系统配置通常分布在源码、服务器目录、WebLogic 控制台、数据库配置表、运维脚本和人工文档中。迁移时要把配置分成几类:环境配置、业务开关、敏感配置、框架配置和灰度配置。

环境配置包括数据库地址、Redis 地址、外部接口地址、文件目录、MQ 地址等,应该进入 Nacos 的环境命名空间或配置分组。业务开关包括是否开启新投保流程、是否走新客户画像接口、是否启用某个营销活动规则,这类配置需要支持动态刷新,但要谨慎控制刷新范围。敏感配置如数据库密码、接口密钥、证书口令不能明文散落在 Nacos,至少要接入公司密钥系统或做加密存储。框架配置如连接池大小、Undertow 线程数、MyBatis 插件、日志级别可以进入统一模板,但生产环境修改必须有审批。灰度配置则要与 Gateway、服务注册元数据或业务路由规则配合。

依赖治理方面,Maven 化后要建立版本收敛机制。建议用父 POM 的 dependencyManagement 统一 Spring Boot、MyBatis、Jackson、日志框架、数据库驱动、连接池、Nacos Client、Gateway 相关版本。对于老 jar,要逐个确认是否还有使用点。可以通过 mvn dependency:tree 排查冲突,通过依赖白名单控制核心版本。典型风险包括:老系统使用 Log4j 1.x,Boot 默认使用 Logback;老系统使用旧 Jackson,Boot 自动配置 ObjectMapper 后序列化格式变化;老系统使用旧 servlet-api,迁移 Undertow 后与 Boot 版本不匹配;MyBatis 和 mybatis-spring 版本组合不兼容;数据库驱动升级后日期、时区、空字符串处理变化。

配置迁移还要处理“启动时配置”和“运行时配置”的边界。例如数据源、日志路径、服务名、Nacos 地址属于启动时配置,动态刷新意义不大,错误刷新反而会造成不稳定;业务阈值、任务开关、降级开关可以动态刷新,但刷新后要记录审计日志。对于保险核心链路,配置发布应该支持灰度:先测试环境,再预发,再生产单实例,最后全量。配置中心不是为了让改配置更随意,而是为了让配置变更可审计、可回滚、可追踪。

6. 容器差异

WebLogic 到 Undertow 的迁移,本质上是从重量级应用服务器转向应用自带运行时。两者的差异会体现在多个细节上。

首先是 ClassLoader 差异。WebLogic 有自己的类加载层级,可能优先加载服务器 lib,也可能通过 prefer-application-packages 调整应用优先。老系统在 WebLogic 上能跑,不代表依赖没有冲突,只是冲突被容器规则隐藏了。迁移到 Boot 可执行 jar 后,依赖由应用自身决定,冲突会更直接地表现为 NoSuchMethodErrorClassNotFoundExceptionLinkageError。处理方式是建立依赖树基线,重点检查 Spring、MyBatis、Jackson、ASM、CGLIB、日志、Servlet API、数据库驱动等高风险库。

其次是 JNDI 和连接池。老应用常通过 java:comp/env/jdbc/xxx 获取 WebLogic 数据源,连接池参数在控制台配置。迁移后通常改为 Boot 配置 DataSource,例如 HikariCP。这个变化不仅是代码层面,还会影响连接池行为:最大连接数、最小空闲、连接校验、泄漏检测、超时、事务隔离级别、自动提交默认值都要重新确认。很多线上问题不是 SQL 变慢,而是连接池参数从 WebLogic 默认值变成 Hikari 默认值后不适配业务峰值。

再次是 Servlet 容器行为。WebLogic 与 Undertow 在请求编码、URL 解码、Header 大小、Cookie 处理、Session 策略、静态资源映射、错误页处理、上传文件大小、异步请求等方面可能有差异。比如老系统依赖 GBK 编码上传文件,迁移后默认 UTF-8 可能导致文件名乱码;老系统上传大附件时 WebLogic 配置了较大请求体限制,Boot 默认限制可能导致请求被拒;老系统通过 web.xml 配置 Filter 顺序,迁移到 Boot 后如果 FilterRegistrationBean 顺序不同,鉴权、编码、日志 MDC 可能失效。

然后是线程模型。WebLogic 有自己的执行线程池,Undertow 有 IO 线程和 Worker 线程。保险销售高峰时,大量同步调用下游接口,如果 Worker 线程被阻塞,接口吞吐会快速下降。迁移时要压测 Undertow 的 io-threadsworker-threads、连接数、超时配置,并结合业务线程池隔离外部接口调用。不能简单认为“内嵌容器更轻,所以默认配置就够”。

最后是运维方式变化。WebLogic 时代运维关注控制台、部署域、节点管理器、WAR 包;Boot 时代关注进程、启动参数、健康检查、日志路径、配置中心、注册中心、容器镜像或脚本。迁移方案必须给运维团队一套清晰的启停、发布、回滚、查看日志、查看健康状态的方法。否则技术栈升级会变成运维风险上升。

7. 验证策略

遗留系统迁移的验证策略必须分层,不能只靠“点页面”。比较稳妥的方式是建立接口、数据、任务、性能和稳定性五类验证。

接口验证关注输入输出一致性。可以从生产访问日志中抽取典型请求,脱敏后形成回放用例,对比老系统和新系统的 HTTP 状态码、响应字段、错误码、关键业务字段。对于保险试算、保费计算、订单提交这类接口,要重点验证金额、费率、折扣、保障期限、险种组合、投保人信息校验等字段。返回 JSON 字段顺序通常不重要,但字段缺失、类型变化、日期格式变化、空字符串和 null 的变化都可能影响前端或调用方。

数据验证关注数据库读写结果一致。对于查询类接口,可以对比结果集数量、主键集合和关键字段。对于写入类接口,不能随意在生产双写,可以在测试环境构造场景,或者在灰度阶段只放小流量,再通过订单状态、流水表、操作日志做对账。涉及事务的场景要重点验证回滚行为,例如订单创建成功但保单提交失败时,老系统和新系统是否保持同样的补偿逻辑。

任务验证关注 Quartz 到 XXL-Job 的迁移。每个任务都要记录原执行频率、执行窗口、是否允许并发、失败是否重试、是否依赖前置任务、是否可以补跑。迁移时可以先让 XXL-Job 以手动触发方式跑通,再切换调度入口。对于日终批处理、客户标签刷新、保单状态同步、短信补偿、报表汇总等任务,要通过执行日志和业务表对账确认结果。最重要的是保证切换窗口内不会出现 Quartz 和 XXL-Job 同时调度同一任务。

性能验证关注迁移前后的容量变化。Spring Boot + Undertow 不一定天然比 WebLogic 快,真正影响性能的是线程池、连接池、SQL、序列化、日志、下游接口和 JVM 参数。压测要覆盖查询高峰、提交高峰、批量导入、文件上传、报表导出、任务并发等场景。指标包括 TP90、TP99、错误率、CPU、内存、GC、数据库连接数、慢 SQL、外部接口耗时、线程池队列长度。迁移前应记录老系统基线,迁移后不能只看平均响应时间。

稳定性验证关注可观测和故障演练。接入 ELK 后,要确认每个请求都有 traceId,Gateway、业务服务、下游调用、定时任务日志能够串起来。要验证 Nacos 配置变更是否可追踪,服务下线后 Gateway 是否正确摘除实例,依赖接口超时时是否有降级或快速失败,日志级别临时调整是否生效。上线前最好做一次小型演练:关闭一个实例、模拟数据库连接耗尽、模拟下游接口超时、模拟配置回滚,观察系统表现和告警链路。

8. 回滚方案

迁移项目没有回滚方案,就不应该进入生产。回滚不只是“把旧包发回去”,而是要围绕流量、配置、数据、任务和依赖关系设计。

最理想的回滚方式是流量回滚。通过 Gateway 路由或负载均衡控制新旧系统流量比例,先让少量查询接口进入新系统,观察稳定后再扩大。如果发现问题,直接将流量切回老系统。这要求新旧系统接口协议保持兼容,数据库写入逻辑不能产生不可逆差异。对于核心写接口,灰度比例要更保守,必要时只对内部账号、特定机构、特定渠道开放。

配置回滚也很重要。Nacos 配置发布前要保留上一版本,生产变更必须记录变更人、变更时间、变更原因和影响范围。出现问题时,能够快速回滚到上一版本,并触发应用刷新或重启。对于高风险配置,例如数据库地址、任务开关、线程池大小,不建议频繁动态修改,可以通过发布窗口控制。

数据回滚最复杂,所以设计时要尽量避免需要数据回滚。迁移期间新系统和老系统最好共用同一数据库模型,减少结构性差异。如果必须改表或新增字段,要保证向前兼容:老系统可以忽略新字段,新系统可以兼容旧数据。数据库变更要遵循“先加后用、先兼容后切换、确认无回滚需求后再清理”的节奏。对于写入链路,可以通过业务流水、操作日志和补偿任务来纠正异常数据,而不是指望直接回滚数据库。

任务回滚要防止重复执行。Quartz 到 XXL-Job 切换时,可以先让老 Quartz 保留但暂停调度,新 XXL-Job 开启;如果回滚,则关闭 XXL-Job 调度,再恢复 Quartz。每个任务要有幂等键,例如业务日期、机构、任务类型、批次号。没有幂等能力的任务不适合直接迁移,应该先补幂等和执行记录。

依赖回滚则要求发布包可追溯。每次发布都要记录 Git commit、Maven 版本、配置版本、数据库脚本版本、镜像或包地址。出了问题能够明确“当前生产运行的到底是哪一版”。这听起来像流程问题,但在遗留系统迁移里非常关键,因为很多事故不是代码不能回滚,而是没人能确定应该回滚到哪个组合。

9. 面试追问

  1. 为什么不能直接重写成 Spring Boot 微服务,而要先做 Maven 化和兼容启动?

  2. Ant 到 Maven 迁移时,如何处理那些公共仓库没有的老 jar?

  3. Spring Boot 自动配置和老 XML Bean 冲突时,你怎么排查?

  4. WebLogic 迁移到 Undertow 后,最容易出现哪些兼容性问题?

  5. 老系统使用 JNDI 数据源,迁移到 Boot 后你如何保证连接池参数一致?

  6. MyBatis 老 XML 很多,怎么确认 Mapper 都被正确加载?

  7. MyBatis 分页插件或拦截器迁移时,为什么插件顺序重要?

  8. 引入 Nacos 后,哪些配置适合动态刷新,哪些不适合?

  9. ELK 接入后,如何保证一次请求的日志能串起来?

  10. Gateway 灰度时,如何避免新老系统接口协议不一致?

  11. Quartz 迁移到 XXL-Job 时,如何保证任务不重复执行?

  12. 如果上线后发现部分订单状态异常,你如何判断是新系统问题、数据库问题还是下游接口问题?

  13. 迁移过程中如何设计回滚?哪些场景无法简单回滚?

  14. Spring3 到 Spring Boot 迁移后,事务行为可能有哪些变化?

  15. 你如何向业务方解释这类技术改造的价值?

10. 推荐回答

如果面试官问“你们为什么要从 Spring3 迁移到 Spring Boot”,可以这样回答:

当时不是为了追新技术,而是老系统已经影响交付和运维。项目还是 Ant 构建,依赖靠手工维护,WebLogic 部署慢,配置散在服务器和控制台,日志排查也比较低效。业务上保险销售和订单流转链路又不能停,所以我们采用分阶段迁移。先把 Ant 改为 Maven,解决依赖和构建可重复;再用 Spring Boot 兼容启动老 XML,逐步替换数据源、事务、MVC 和配置;然后从 WebLogic 迁移到 Undertow,最后接入 Nacos、Gateway、ELK 和 XXL-Job。这样风险可控,每一步都有验证和回滚。

如果面试官问“迁移过程中最难的点是什么”,可以这样回答:

最难的不是写 Boot 启动类,而是处理老系统里的隐性依赖。比如 WebLogic 提供的 JNDI 数据源、类加载顺序、连接池默认参数、部署描述符、Session 和编码配置,迁移到 Undertow 后都要显式配置。还有 MyBatis 的 XML、插件、TypeHandler、分页逻辑,稍微不一致就可能影响查询结果。我们当时的做法是先做资产盘点和基线验证,把接口、任务、SQL、配置和依赖都列出来,再按风险分阶段迁移。核心交易链路最后迁,查询和运营类功能先迁。

如果面试官问“MyBatis 兼容怎么做”,可以这样回答:

我们没有一开始就重写 Mapper,而是尽量保持老 XML 不动。Boot 侧配置 SqlSessionFactory、Mapper 扫描、typeAliasesPackage、typeHandlersPackage 和插件列表,保证和老系统一致。迁移时重点检查 XML 是否全部加载、命名空间是否和接口匹配、分页插件顺序是否一致、事务管理器是否同一个 DataSource。验证上会抽取生产典型查询做结果对比,尤其关注分页、排序、动态条件、日期和空值处理。

如果面试官问“WebLogic 到 Undertow 有哪些坑”,可以这样回答:

主要是容器能力差异。WebLogic 是完整应用服务器,很多能力在容器里,比如 JNDI、连接池、安全域、类加载规则、线程池和部署描述符。Undertow 是内嵌 Servlet 容器,这些能力要回到应用配置里。我们重点处理了 JNDI 数据源改造、连接池参数对齐、Servlet 编码和上传大小限制、Filter 顺序、错误页、Session 策略、Header 限制和 Undertow 线程参数。上线前会用压测和生产日志回放对比。

如果面试官问“Quartz 迁移到 XXL-Job 如何防止重复执行”,可以这样回答:

先盘点每个任务的调度表达式、执行窗口、是否允许并发、失败重试和业务幂等键。迁移时不让 Quartz 和 XXL-Job 同时调度同一任务,一般先暂停 Quartz,再打开 XXL-Job。任务代码里补执行记录和幂等控制,比如按业务日期、任务类型、机构或批次号去重。对于日终批处理和状态同步任务,还会加结果对账和手动补偿入口。

如果面试官问“如何设计回滚”,可以这样回答:

回滚分几层。流量层通过 Gateway 或负载均衡把流量切回老系统;配置层通过 Nacos 版本回滚;任务层关闭 XXL-Job 调度并恢复 Quartz;应用层保留上一个可运行包和配置组合;数据层尽量不做物理回滚,而是通过向前兼容的表结构、业务流水和补偿任务修正。核心原则是迁移设计时就避免不可逆变更,比如先加字段不删字段,接口保持兼容,新老系统可以在一段时间内并行。

如果面试官问“ELK 和 traceId 怎么落地”,可以这样回答:

Gateway 入口生成或透传 traceId,放到 Header 和 MDC 中。业务服务的 Filter 或 Interceptor 读取 traceId,写入 MDC,调用下游接口时继续透传。日志格式统一输出时间、应用名、实例、traceId、用户或机构标识、接口名、耗时、错误码。这样在 Elasticsearch 里按 traceId 就能看到一次请求从网关到业务服务再到下游调用的日志。定时任务也会生成 taskId 或 traceId,方便排查批处理问题。

11. 延伸学习路线

第一阶段建议补 Spring Boot 迁移基础。重点学习 Boot 自动配置原理、条件装配、配置绑定、外部化配置、Starter 机制、应用启动流程、Bean 生命周期、事务自动配置和 Web MVC 自动配置。不要只背 @SpringBootApplication,要能解释为什么老 XML 可以通过 @ImportResource 兼容,为什么自动配置可能和手工 Bean 冲突。

第二阶段学习 Maven 和依赖治理。要熟悉 dependencyManagement、parent、BOM、scope、optional、exclusion、profile、私服、依赖树分析、版本冲突定位。遗留系统迁移里,Maven 能力往往比框架 API 更能体现工程经验,因为很多事故都来自依赖不可控。

第三阶段学习 Servlet 容器和运行时差异。重点看 Tomcat、Jetty、Undertow 的基本线程模型、连接参数、请求限制、Filter/Listener/Servlet 注册方式、Session、编码、异常页和健康检查。再对比 WebLogic 这类应用服务器提供的 JNDI、JTA、连接池、ClassLoader 和部署模型,就能理解为什么容器迁移不是简单换端口。

第四阶段深入 MyBatis。建议掌握 SqlSessionFactory、MapperProxy、Executor、StatementHandler、ParameterHandler、ResultSetHandler、插件拦截点、TypeHandler、动态 SQL、一级缓存、二级缓存和 Spring 事务集成。面试中如果能把“老 XML 兼容”和 MyBatis 执行链路结合起来讲,会比单纯背源码更有说服力。

第五阶段学习微服务配套治理。Nacos 要理解配置中心、注册发现、命名空间、分组、动态刷新和配置回滚;Gateway 要理解路由、断言、过滤器、限流、鉴权、超时、灰度;ELK 要理解日志格式、MDC、traceId、索引设计和检索;XXL-Job 要理解调度中心、执行器、分片、失败重试、阻塞策略和任务幂等。

第六阶段学习迁移方法论。可以用“资产盘点、风险分级、兼容启动、双轨验证、灰度切流、可观测建设、回滚预案、复盘沉淀”这八个关键词总结。资深 Java 面试里,面试官更关心你是否能把复杂系统拆成可执行步骤,而不是是否知道某个注解的用法。真正有价值的回答,应该始终围绕业务连续性、风险控制、工程治理和可验证结果展开。