Java面试复盘:Spring Boot、微服务与AI技术栈实战
说实话今年准备大厂Java面试给我最大的感受是单纯背八股文已经不够用了。我去年列复习清单时第一行还是“Java基础JVM、集合、并发”结果面了两三家之后发现面试官问得最多的其实是另外三样东西——Spring Boot的自动装配原理、微服务的拆分边界、以及你有没有碰过AI相关的项目。“Spring Boot、微服务与AI技术栈”这三个词放在一起看起来很宽但它恰恰是当前互联网大厂Java后端招聘的真实状态。用Spring Boot写CRUD已经不算竞争力微服务是团队协作的基本形态而AI技术栈正在快速渗透到后端业务里。这篇文章把我自己的面试准备过程、高频考点、答题逻辑、项目话术和踩坑记录完整复盘一遍。无论你是准备秋招的应届生还是打算跳槽的资深开发都可以照着这个思路做查漏补缺。1. 面试准备的整体思路技术栈漂移背后的招聘逻辑1.1 “Java八股文”到底还值不值得背“Java八股文”这个词在社区里褒贬不一。我的态度很明确八股文是敲门砖但只是敲门砖。面试官问“HashMap在JDK 8里有什么变化”“volatile和synchronized的区别”本质上不是在考你记忆力而是在看看你有没有认真读过源码、有没有在并发场景里真正踩过坑。所以可以背但要带着为什么去背。我在复习时把八股文分成两类。一类是“原理必答”比如JVM内存模型、类加载机制、ConcurrentHashMap的锁粒度、Spring Bean的生命周期这些是Java工程师的基本盘答不好基本一票否决。另一类是“场景推导”比如“线上CPU飙高你怎么排查”“数据库连接池怎么设置大小”这类题没有标准答案重点听你的排查思路和决策依据。我的建议是八股文一轮复习当作知识点扫盲二轮复习必须做到能用自己的话复述。检验标准很简单——你能不能给一个完全不懂Java的人讲明白“为什么要有GC”。如果只能背定义那面试官再追问两句就会露馅。1.2 复习顺序怎么排从基础到 AI 的完整路线我这一路复习下来觉得最有效的顺序是“基础理论 → 框架原理 → 分布式工程化 → 业务实战 → AI 扩展”五步走。第一步是Java基础包括集合源码、并发工具、JVM调优、IO模型这一层决定你的下限。第二步是Spring Boot和MyBatis的原理不只是会注解要能讲清楚自动装配发生了什么、Mapper代理是怎么生成的。第三步是微服务全套注册中心、配置中心、网关、熔断限流、分布式事务这一层决定你能不能在大团队里生存。第四步是找一个真实项目把前面所有知识点串起来项目不在大在于能不能讲出取舍。第五步才是AI技术栈用大模型API或开源模型做一个真实场景的小应用这在简历上是明显的差异化亮点。很多人一上来就刷“java面试题和答案”合集我强烈不建议这么做。没有知识体系支撑的刷题效率低而且容易忘。一套题做三遍不如把背后的原理吃透一遍。1.3 JDK版本从Java 8到17/21的语法分水岭现在面试聊到Java版本是个很有意思的分歧点。存量业务大多还在Java 8但新项目已经开始用Java 17/21了。我发现面试官喜欢问“Java 8和Java 17有什么区别”其实考察的是你对技术演进的敏感度。Java 17带来的switch表达式、record类、文本块、instanceof模式匹配这些不光是语法糖它们能真实改变你写代码的方式。比如record类替代了大量样板代码的POJO在写领域模型时非常舒服。Java 21进一步引入了虚拟线程这个在IO密集场景下是降维打击。这里顺带说一个实际环境问题热搜里经常看到“麒麟V10 Java 18安装”和“java环境变量使用多个jdk”。实际工作中经常需要在Linux服务器上装JDK最常见的方式是用tar.gz包解压到指定目录然后通过/etc/profile.d/下写脚本设置JAVA_HOME和PATH。如果服务器上需要多个JDK共存我的做法是在profile脚本里用变量切换哪个项目需要哪个版本就改JAVA_HOME的指向而不是反复修改系统默认PATH。能说清楚这套环境配置逻辑在面试聊到部署时反而会加分因为它说明你真的上过服务器。2. Spring Boot与MyBatis高频追问面试官到底想听什么2.1 自动装配与条件注解最经典的“读过源码”试金石Spring Boot的自动装配是被问得最频繁、也最容易被答成背诵腔的知识点。我建议每个准备面试的人都能用自己的话把这个过程完整讲明白不要只甩出“SpringBootApplication是组合注解”这个结论。完整的链路是这样的SpringBootApplication由SpringBootConfiguration、EnableAutoConfiguration、ComponentScan三个注解组成。其中EnableAutoConfiguration通过Import导入AutoConfigurationImportSelector这个Selector会读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件里声明的所有自动配置类。但注意它不是一股脑全部生效而是逐个用ConditionalOnClass、ConditionalOnProperty、ConditionalOnBean等条件注解去判断当前环境是否满足装配条件。面试官在这个问题上喜欢连环追问。比如“如果我自己写一个 starter怎么保证只在我需要的时候加载”“ConditionalOnClass失效了怎么排查”。应对方法也很直接自己动手写一个自定义starter哪怕只是打印一行日志的demo你会立刻理解为什么需要条件注解、为什么需要配置元数据。我在复习时花了一个周末写了两个starter其中一个是根据配置文件开关控制是否启用后面所有关于自动装配的追问都答得比较顺。理解这一点还能帮你理解现象背后的原因。比如为什么spring.factories在新版Spring Boot里不生效了为什么自定义配置类要放在启动类扫描不到的包时需要手动ComponentScan。这些细节才是面试官眼里“有源码阅读习惯”的表现。2.2 MyBatis与MyBatis-Plus从Mapper到建表SQLMyBatis也是高频区。基础问题包括MyBatis的一级缓存和二级缓存、$和#的区别、Mapper接口能不能重载。进阶一点会问Mapper代理的生成原理也就是在启动时通过MapperScannerRegistrar扫描接口给每个接口生成MapperProxy工厂调用方法时通过SqlSession执行预编译SQL。把这个讲清楚比单纯说“MyBatis简化了JDBC”要高级得多。现在很多项目用MyBatis-Plus面试官也会跟着问。MyBatis-Plus的BaseMapper自带CRUD方法本质上是根据实体类上的TableName、TableId、TableField注解在运行时拼接SQL模板。比如selectById对应的SQL就是在TableInfo里根据主键字段动态生成的。有个热搜是“mybatisplus根据java实体类生成创建表的sql语句”这个需求在“代码先行”的开发模式里很常见。MyBatis-Plus本身没有对外提供稳定的建表API但你可以通过TableInfo拿到实体类的全部元信息包括表名、字段名、字段类型、主键然后自己拼接DDL。实际项目中我们一般不会在生产环境让程序自动建表但用实体类生成一次性的初始化脚本是很实用的操作尤其在多环境数据库结构同步的场景。我的建议是面试时主动提到“BaseMapper的CRUD不满足复杂查询时我会用Select或自定义XML”这能避免给面试官留下“只会用ORM不会写SQL”的印象。毕竟MyBatis的本质是半自动ORMSQL掌控力才是核心竞争力。2.3 启动配置、端口切换与Linux部署细节里见功夫Spring Boot的启动配置属于“面试不会专门考但线上排查天天用”的知识点。就说“spring boot修改端口号”这种看起来简单的问题其实有四种改法修改application.yml、通过命令行参数--server.port8081、通过环境变量SERVER_PORT、以及用SpringBootApplication启动时手动设置SpringApplication对象属性。关键在于优先级。Spring Boot的配置优先级从高到低大致是命令行参数 Java系统属性 环境变量 application-{profile}.yml application.yml 默认配置。我身边有同事在本地起多个服务时端口一直冲突就是因为没搞清楚命令行参数的优先级比配置文件高改了yml不生效最后发现是IDE启动参数里写死了端口。部署方面很多团队还停留在“本地能跑就行”但面试聊到项目落地能力时打包部署是绕不开的。Java项目打成tar包发布是Linux服务器上非常常见的动作尤其是配合systemd或shell脚本做启停。我的标准操作是maven打包出可执行jar再把jar、配置文件、启停脚本、日志目录一起打进tar包解压后通过脚本调用java -jar启动。你不需要是运维专家但至少要知道启动参数怎么写、日志怎么重定向、进程怎么优雅关闭。这些细节一旦在面试里自然带出来会比说一万句“熟悉Linux”都有说服力。3. 微服务架构面试从画图到拆分的完整回答框架3.1 服务拆分边界拿电商系统当例题“微服务拆分”几乎是必考题。面试官一般会给你一个系统比如多商户商城问你怎么拆。很多人的答案就四个字“按业务拆”这等于没答。真正的答题框架应该是先讲拆分原则再讲具体服务划分最后讲数据拆分和通信方式。拆分原则我喜欢用“领域边界”而非“功能模块”来定义。还是拿多商户跨境商城举例用户、商品、订单、支付、物流、商户、营销、消息通知这些并不只是功能模块每个都有自己独立的业务规则和数据边界。用户关注账号安全和会员等级商品关注类目和库存SKU订单关注状态机和金额计算。如果只是把原来的大单体代码按Controller复制到不同服务里那叫“微服务搬家”不叫“微服务拆分”。一个我实际用过的判断标准是如果两个功能频繁需要一起修改、一起发布或者数据的强一致性要求极高那它们就应该先留在一个服务里。服务的边界不是越细越好而是要让团队能够独立开发、独立部署、独立扩展。我在面试里会主动提“我们有一个服务一开始拆得很细结果一次需求变更要跨五个服务改代码联调成本翻倍”这种真实教训比理论说一百句都值钱。3.2 架构图怎么讲把组件串成一条调用链“微服务架构图”这个热搜词说明很多人卡在怎么画图和讲图上。其实面试官想看的是你能不能把注册中心、配置中心、网关、认证、消息队列、缓存、监控这些组件在自己的项目里讲出逻辑关系。我的讲法是把架构图当成一次请求的旅行来叙述。用户请求先打到Nginx或云负载均衡再到Spring Cloud Gateway做路由和鉴权Gateway根据路径把请求转发到具体的微服务微服务之间通过OpenFeign做内部调用服务实例的地址从Nacos注册中心获取配置从Nacos配置中心拉取涉及异步场景的通过RocketMQ或Kafka解耦热点数据在Redis里缓存最终数据落到各自的数据库或分库分表里。这个叙述里有三个细节很加分。第一是“服务发现”和“负载均衡”的关系Feign集成了Ribbon或Spring Cloud LoadBalancer通过服务名而不是IP去调用。第二是“网关和注册中心的配合”网关自身也要注册到注册中心才能动态感知路由的服务列表。第三是“配置中心为什么需要”因为微服务实例可能几十个改一个配置不能逐个登录服务器改必须通过配置中心推送。3.3 VSCode统一启动多个微服务本地联调的效率神器本地开发联调是微服务最大的痛点之一。如果你的项目有五个微服务每次改个接口都要手动启动五个进程光等启动就浪费十分钟。很多团队用IDEA的Run Configuration一个个启动也有人会把所有服务塞进一个Spring Boot聚合模块里跑但这些方式在多模块多仓库场景下并不方便。我后来发现VSCode的launch.json可以配置多个Java微服务统一启动这个用法对喜欢轻量编辑器的人特别管用。在项目根目录的.vscode/launch.json里给每个微服务定义一个configurationtype用javarequest用launchmainClass指向每个服务启动类projectName对应你的模块名。然后关键一步是用compounds把多个configuration编排在一起点一次运行所有配置的服务就会按列表依次启动。{ version: 0.2.0, configurations: [ { type: java, name: gateway-service, request: launch, mainClass: com.demo.gateway.GatewayApplication, projectName: gateway-service }, { type: java, name: user-service, request: launch, mainClass: com.demo.user.UserApplication, projectName: user-service }, { type: java, name: order-service, request: launch, mainClass: com.demo.order.OrderApplication, projectName: order-service } ], compounds: [ { name: Start All Microservices, configurations: [gateway-service, user-service, order-service] } ] }这种配置我第一次弄的时候也踩了点坑主要是projectName必须和pom.xml里的artifactId或者Gradle的project name一致否则VSCode的Java扩展找不到对应的类路径。另外一个细节是如果某个服务启动时依赖注册中心最好把注册中心也纳入同一套启动流程或者先手动启动中间件再启动整个compounds。3.4 分布式数据一致性面试连环炮的标准应对“Java怎么保证数据一致性”这个话题从单体聊到分布式跨度很深。单体阶段其实相对简单JVM内存并发靠volatile、synchronized、Lock和CAS数据库层面靠本地事务ACID这是Java并发编程的基本功。真正麻烦的是分布式环境下跨服务跨数据库的一致性怎么保证。面试官一般会给你一个经典场景“订单服务扣库存同时需要调用积分服务加积分其中一个失败怎么办”。我的回答框架分四层。第一层能不用分布式事务就不用优先通过接口幂等和异步重试解决最终一致性。第二层如果必须保证可以从本地消息表开始把“扣库存”和“写消息表”放在同一个本地事务里然后靠消息队列异步消费消费方做幂等处理。第三层数据量更大再考虑RocketMQ的事务消息或者Seata的AT模式/TCC模式。第四层一定要说清AT模式的全局锁和回滚日志原理这是区分背题和懂原理的分水岭。这里有一个很多面试者都会犯的错误把“消息丢失”和“重复消息”混为一谈。其实大部分消息中间件在极端情况下都做不到只发一次所以业务侧必须实现幂等。我在回答时会主动补充“幂等有三种常见方案唯一索引、状态机、分布式锁比如支付回调场景就靠订单状态机和唯一流水号挡住重复请求”这几句话能明显让面试官觉得你有实战经验。3.5 开源脚手架学习法以若依微服务版为例现在很多应届生的项目经验都来自开源脚手架比如若依微服务版。这不是坏事关键在于你怎么把它变成自己的东西。面试官也清楚大家会用开源项目所以他看重的是你对这个项目的理解深度而不是“用过”这个事实。我建议拿到若依这类脚手架之后不要急着跑起来就往简历上写。花一周时间做三件事。第一画出它的服务拆分图搞清楚每个模块的业务职责和技术职责。第二把你最熟悉的业务链路串一遍比如用户登录如何走网关认证、如何获取token、如何鉴权。第三找一个你觉得“设计得不够好”的点比如某处权限判断没有做缓存或者某段事务范围过大然后给出你的改造方案。举个例子行级权限就是这个项目里的一个常见考点。若依微服务版里有数据权限注解但很多用它做二次开发的人根本说不清底层实现。其实它是通过MyBatis-Plus的DataPermissionInterceptor拦截SQL根据当前用户角色拼接数据范围条件。如果面试官问你“怎么实现用户只能看到本部门订单”你能从拦截SQL这个层面去回答而不是说“加个where条件就行了”那就完全是两个档次。另外要记住简历上写开源脚手架项目没问题但必须能扛住“这个功能是不是你做的”“这部分你是怎么设计的”这类深挖。4. AI技术栈Java程序员的差异化加分项4.1 大模型应用开发为什么进入Java面试范围这两年大模型应用开发的热度从Python社区蔓延到了后端开发Java面试也开始问AI原因并不复杂业务方希望在后端系统里接入智能客服、知识库问答、简历解析、商品描述生成等能力而这些功能最终都要落到Java写的微服务里。搜“java ai智能应用开发训练营”的人越来越多说明很多Java程序员开始补这块知识。但面试官并不会要求你用Python训练模型他更关心你有没有能力把大模型能力工程化地集成进现有系统。换句话说关键是“能不能调通API、能不能设计好Prompt、能不能做RAG、能不能控制成本、能不能保证响应速度”。我在准备阶段给自己定了一个目标不谈AI基础概念只讲能落地的方案。面试时提到“我在项目里接入了大模型做知识库问答”比说十句“我了解Transformer原理”要更有说服力。4.2 Java做AI的路径Spring AI与LangChain4j很多Java开发者有一个误解AI是Python的专利Java做不了。这句话对训练模型成立对应用开发完全不成立。现在Java生态已经有大模型应用开发框架比如Spring AI和LangChain4j都能很好地接入OpenAI、通义千问、DeepSeek等国内外大模型API。我实际体验下来的感觉是用Java做RAG并没有想象中那么困难。核心链路是先对文档做切片用Embedding模型把切片向量化存入向量数据库用户提问时也向量化然后在向量库里做相似度检索把检索到的相关文本片段和用户问题一起组装成Prompt发给大模型让它基于参考内容回答。Java侧的向量数据库客户端、HTTP调用、异步处理都比Python顺手因为这些都是后端工程师的日常。这里还得说清Python和Java在AI方向的分工。用生活化的类比来说Python像实验室里的研究员负责探索和训练模型Java像工厂里的产线工程师负责把成熟模型稳定地跑起来、大规模地服务用户。面试官问“你不是做算法的为什么能做AI项目”你就用这个类比回答既清晰又能体现工程思维。4.3 简历中落地AI项目的三条思路简历里写AI项目我建议选择那些业务价值明确、技术链路完整、能讲出量化效果的方向。这里整理出三个我在面试中见到的比较成功的思路。第一个是智能客服或工单自动分类。把用户的问题和历史工单作为知识源做RAG大模型生成回复草稿人工审核后发送。技术点包含文档解析、向量检索、Prompt工程、人机协同。第二个是简历解析和岗位匹配。用大模型抽取简历里的技能关键词和工作年限然后和职位JD做语义匹配输出匹配度和缺失项。这个项目如果做过面试官通常会很感兴趣因为它涉及信息抽取、结构化输出、规则引擎和大模型结合。第三个是内部知识库问答把公司内部文档、API文档做成一个内部聊天机器人考核指标是检索准确率和回答引用率。简历上不要只写“使用了LangChain4j和向量数据库”要写清楚你调用了哪几个组件、怎么评估效果、上线后遇到了什么幻觉问题、你又是怎么通过Prompt或上下文压缩缓解的。这些都是面试官真正想听的内容。5. 笔面试实操与避坑记录5.1 手撕代码的常见考题排序与sort源码大厂笔试和现场手撕代码排序是永远绕不开的。有个热搜叫“冒泡排序java”很多新手觉得冒泡太简单不用准备但真到了面试白板上写能一次写对边界条件的人并不多。我建议把冒泡排序、选择排序、插入排序、归并排序、快排这五种都自己默写过一遍重点是控制循环边界和算清楚时间复杂度。public static void bubbleSort(int[] arr) { if (arr null || arr.length 2) { return; } for (int i 0; i arr.length - 1; i) { boolean swapped false; for (int j 0; j arr.length - 1 - i; j) { if (arr[j] arr[j 1]) { int tmp arr[j]; arr[j] arr[j 1]; arr[j 1] tmp; swapped true; } } if (!swapped) { break; } } }“sort函数用法java”这个热搜也值得展开一下。日常开发中很少手写排序用的都是Arrays.sort和Collections.sort但面试官会追问“底层用的什么排序算法”。这题的答案是基本类型数组用的DualPivotQuicksort双轴快排对象数组用的TimSort归并排序优化版。为什么对象要用TimSort因为归并排序是稳定排序相同key的对象不会因为排序而交换相对位置。回答完这两句话再主动补充“所以如果需要稳定排序就使用对象数组而不是基本类型数组”会显得你既懂API又懂源码。5.2 面试现场的整体节奏控制很多面试者最大的问题不是不会而是没有答题节奏感。我总结出来的经验是遇到任何一个问题先判断它是“原理题”“场景题”还是“项目题”然后采用不同的答题结构。原理题先说结论再用一两句话展开原理最后补一个使用场景。比如问“什么是CAP定理”我会说“CAP是分布式系统的三个核心属性一致性、可用性、分区容错性分区容错是必须选择的所以实际是在一致性和可用性之间做取舍”然后立刻接一个所在项目的选型例子。场景题先说业务背景再说你当时的设计思路最后说取舍和代价。项目题只讲一个原则讲细节不讲流水账。面试官问“你这个项目数据库怎么设计的”不要从建表开始讲直接说核心表有哪些、主键策略、索引怎么建、分库分表怎么做的。还有一个小技巧面试官深挖项目时热门话题“行级权限”是一个特别好的测试点。如果你在项目里做过数据权限可以用“我在订单管理里实现了按部门控制数据范围核心思路是自定义MyBatis-Plus拦截器解析数据权限注解根据当前登录人的组织ID动态拼接SQL条件”这种回答来展示实战能力。这种具体到拦截器层面的回答比空泛说“我用Shiro做了权限控制”要扎实很多。5.3 高频失误与排查我自己踩过的坑面试踩坑这件事几乎每个人都会经历我也一样。第一个高频失误是简历上写了“精通Spring Cloud”但被问到“Nacos集群模式下临时实例和持久实例的区别”时答不上来。这类问题的根源在于简历用词太大实际上只是用过几个组件。我的经验是把“精通”改成“掌握”“掌握”改成“了解”反而更容易掌握面试主动权。第二个坑是聊项目时把框架API当成项目亮点。比如“我在项目里使用了Redis缓存”这不算亮点。面试官关心的是缓存什么数据、缓存击穿怎么预防、过期策略怎么选、缓存和数据库的一致性怎么保证。我从第三次面试开始调整策略所有技术点都至少准备一个“业务场景—技术方案—权衡代价”的完整结构明显感觉聊天深度上去了。第三个坑是我在准备AI项目时差点踩进去的——把RAG吹得太满。刚开始我告诉面试官“知识库问答准确率95%”结果被追问“另外5%怎么分析”“冷启动时检索为空怎么办”。后来我学会了对自己的数据指标打折扣并主动说出局限性和改进方案。面试官要的不是完美答案是你有没有持续思考的习惯。第四个值得单独说的问题是“java进程”排查类的场景题。面试官可能会问“线上一个Java进程CPU飙到100%你怎么排查”。完整的套路是先用top找到高CPU的进程PID再用top -Hp PID找到高CPU线程的TID把TID转成十六进制用jstack导出线程快照搜索nid定位到具体代码行。这个排查链路我建议每个人都实际在本地做一遍数据局模拟因为面试官很容易从jstack命令继续追问“有些线程状态是WAITING有些是RUNNABLE分别代表什么”没有实践经验很难答得流畅。回看这一整轮的面试准备我最大的收获其实是心态上的转变。以前总觉得面试是“被审判”后来发现面试更像一场技术答辩面试官想知道你会什么、怎么思考、能不能一起干活。Java生态已经不像十年前那样只靠SSH就能混饭吃Spring Boot 微服务 AI技术栈的组合正在成为大厂后端的基本盘。准备过程中不用贪多求全把每个知识点吃透到能讲出“为什么”的深度比盲目背一万道面试题要可靠得多。最后再分享一个亲测有效的小方法每天晚上把当天复习的知识点用手机录音给自己讲一遍讲完再回听你很快就能发现自己哪里其实还没懂。这个方法陪我走过了最难熬的一个月也希望能帮到你。