Java大厂面试实录:谢飞机的奇幻之旅
场景:某互联网大厂会议室,资深Java架构师李严肃正襟危坐,面前坐着笑容灿烂、自信满满的求职者——谢飞机。
人物:
- 李严肃:技术深厚,不苟言笑,擅长层层递进式提问。
- 谢飞机:基础尚可,能答简单问题,一遇深水区就“起飞”,口头禅是“这个我用过,但具体实现……嘿嘿”。
第一轮:基础与框架(Spring Boot 启动篇)
李严肃:谢飞机同学,请介绍一下你对Spring Boot自动装配的理解。它是如何工作的?
谢飞机:哦!这个我知道!Spring Boot超好用的,加个@SpringBootApplication注解,项目立马跑起来,省了好多配置!它会自动扫描包,把Bean都注册进去,特别智能!
李严肃:嗯,不错。那你能说说@SpringBootApplication里面包含了哪些核心注解吗?
谢飞机:有@ComponentScan!还有@Configuration……还有一个,三个字母的,叫什么来着……@XXX……哎呀,一时想不起来了,但我用过!
李严肃:那是@EnableAutoConfiguration。它又是如何实现“自动”的呢?
谢飞机:嗯……它是通过读一个文件……好像是spring.factories?对!它会去META-INF下面找这个文件,然后把里面配的类都加载进来。就像插件一样,插上就能用!
李严肃:很好,理解得比较到位。那么,如果我想自定义一个Starter,该怎么做?
谢飞机:自定义Starter?这个……我们公司都是直接用现成的,比如spring-boot-starter-web。自定义的话,应该也是建个新项目,然后写个spring.factories文件放进去吧?具体细节……我回头可以学一下!
第二轮:数据库与性能(MyBatis 深水区)
李严肃:我们换个话题。在电商场景中,商品详情页的QPS很高,你是如何优化数据库查询性能的?
谢飞机:这简单!加索引啊!查询慢就explain一下,看执行计划,哪里走全表扫描就给它加上索引!立竿见影!
李严肃:如果单靠数据库扛不住了呢?
谢飞机:那就上缓存呗!Redis!把商品信息缓存起来,先查Redis,没有再查数据库,查到了再回填到Redis。我还会用@Cacheable注解,一行代码搞定!
李严肃:缓存穿透怎么办?
谢飞机:缓存穿透?哦!就是查一个根本不存在的数据,每次都绕过缓存打到数据库。这个……我们可以给空值也缓存一下,比如缓存个特殊字符串,这样下次就知道它不存在了。时间可以设短一点。
李严肃:缓存雪崩呢?
谢飞机:缓存雪崩?是不是……就是很多缓存同时失效了?然后请求全涌向数据库?这个……好像可以用随机的过期时间?让它们别一起死。还有,主从复制、读写分离也能分担压力,对吧?
李严肃:最后一个问题,你的SQL是手写的还是用MyBatis Generator生成的?手写SQL时,如何防止SQL注入?
谢飞机:我们都用Generator!效率高!手写的话……嗯……我一般用#{},不用${},听说${}会有问题。具体原理嘛……#{}好像是预编译?能防注入。${}就是直接拼接,危险!
第三轮:微服务与分布式(Spring Cloud 迷雾)
李严肃:在微服务架构下,服务A调用服务B,如果B挂了或者响应很慢,会发生什么?
谢飞机:哦!这个我知道!会卡住!A也会变慢,然后A的线程都被占满了,最后A也挂了!这就是雪崩效应!
李严肃:如何防止?
谢飞机:用Hystrix!熔断!当B失败率达到一定比例,Hystrix就直接不让A调用B了,返回一个默认的降级结果,比如“商品信息获取失败”。等B恢复了,再慢慢尝试调用。
李严肃:Hystrix已经停止维护了,现在主流是什么?
谢飞机:啊?停更了?那……那我们还用Hystrix啊。没听说过新的……Resilience4j?听名字好像也是干这个的。它们应该差不多吧?
李严肃:服务之间的通信,除了HTTP Rest,还有什么方式?
谢飞机:当然有!RPC!比如Dubbo!比HTTP快!Dubbo用的是Netty做网络通信,序列化可以用Hessian、Protobuf。
李严肃:如果让你设计一个API网关,你会考虑哪些核心功能?
谢飞机:API网关?就是Zuul或者Spring Cloud Gateway吧?核心功能……要有路由,能把请求转发到不同的微服务。还要有负载均衡,选个健康的实例。安全方面,统一鉴权,比如校验JWT token。哦对,还有日志记录和监控!
李严肃:很好,今天的面试就到这里。你的基础还不错,有些地方还需要深入。回去等我们的通知吧。
谢飞机:好的好的,谢谢面试官!我回去一定好好复习!
面试官的答案详解
第一轮答案:Spring Boot 自动装配
业务场景
在现代Java开发中,快速搭建项目骨架是基本要求。Spring Boot的自动装配机制极大地简化了这一过程,让开发者能专注于业务逻辑,而非繁琐的配置。
技术点解析
-
@SpringBootApplication注解:这是一个组合注解,包含了三个核心部分:@SpringBootConfiguration:标识这是一个Spring Boot的配置类(本质是@Configuration)。@EnableAutoConfiguration:开启自动装配的核心开关。@ComponentScan:指定要扫描的包路径,发现并注册@Component,@Service,@Repository,@Controller等注解的Bean。
-
@EnableAutoConfiguration的工作原理:- 它会查找所有jar包下的
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件(Spring Boot 2.7+)或旧版的META-INF/spring.factories。 - 这些文件里声明了大量以
XxxAutoConfiguration命名的配置类。 - Spring Boot会根据条件注解(如
@ConditionalOnClass,@ConditionalOnMissingBean,@ConditionalOnProperty)来决定是否加载这些配置类。例如,只有当classpath下存在DataSource.class时,DataSourceAutoConfiguration才会生效。
- 它会查找所有jar包下的
-
自定义Starter:
- 创建一个Maven/Gradle项目,引入
spring-boot-autoconfigure依赖。 - 编写一个或多个
XxxAutoConfiguration配置类,并使用条件注解进行约束。 - 在
src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中,添加你的自动配置类的全限定名。 - 最终打包发布,其他项目只需引入你的Starter依赖,即可获得开箱即用的功能。
- 创建一个Maven/Gradle项目,引入
第二轮答案:数据库与缓存优化
业务场景
在电商、内容社区等高并发场景中,热门商品或文章的访问量巨大。如果每次请求都穿透到数据库,数据库将不堪重负,导致响应延迟甚至宕机。
技术点解析
-
索引优化:这是SQL优化的第一步。合理使用B+树索引,避免全表扫描。
EXPLAIN命令是分析SQL执行计划的利器。 -
缓存策略 (Redis):
-
缓存穿透:指查询一个数据库中根本不存在的数据,导致缓存层和数据库层都查不到,请求直接打到数据库。解决方案:
- 缓存空对象:即使数据库查询结果为空,也将一个特殊的空值(如
null或特定字符串)写入缓存,并设置较短的过期时间(如5分钟),防止同一无效Key被反复查询。 - 布隆过滤器 (Bloom Filter):在缓存层前加一层布隆过滤器。它是一个空间效率极高的概率型数据结构,用于判断一个元素“一定不存在”或“可能存在”。对于确定不存在的Key,直接拒绝查询,避免访问缓存和数据库。
- 缓存空对象:即使数据库查询结果为空,也将一个特殊的空值(如
-
缓存雪崩:指大量缓存数据在同一时间点集中失效,导致瞬时大量请求直接涌向数据库。解决方案:
- 设置随机过期时间:在原有缓存过期时间的基础上,增加一个随机值(如1-5分钟)。例如,
expireTime = baseTime + random(60, 300),使缓存失效时间分散开来。 - 构建高可用缓存集群:使用Redis Cluster等方案,避免单点故障。
- 限流降级:在数据库层或服务层实施限流(如Guava RateLimiter)和降级策略,保护系统核心功能。
- 设置随机过期时间:在原有缓存过期时间的基础上,增加一个随机值(如1-5分钟)。例如,
-
-
SQL注入防护 (MyBatis):
#{}vs${}:#{}:会被MyBatis解析为PreparedStatement的参数占位符?。它会对传入的参数进行预编译和类型安全检查,能有效防止SQL注入。${}:是纯粹的字符串替换,在SQL语句构建阶段就直接将变量值拼接到SQL中。如果变量来自用户输入,极易引发SQL注入攻击。
- 最佳实践:除非万不得已(如动态表名、列名排序),否则一律使用
#{}。永远不要将用户输入的内容用${}直接拼接到SQL中。
第三轮答案:微服务容错与通信
业务场景
微服务架构将单体应用拆分为众多独立的服务。这种松耦合带来了灵活性,但也引入了网络延迟、服务宕机等不稳定性因素。必须有完善的机制来保证系统的整体健壮性。
技术点解析
-
服务雪崩效应:当一个服务(下游B)出现性能瓶颈或宕机时,调用它的服务(上游A)会因等待响应而耗尽自身资源(如线程池),最终导致A也发生故障,故障像雪崩一样蔓延至整个系统。
-
熔断器模式 (Circuit Breaker):
- Hystrix:Netflix开源的经典熔断器库,已进入维护模式。
- Resilience4j:新一代轻量级、函数式容错库,专为Java 8和函数式编程设计。它是目前Spring Cloud官方推荐的替代方案。其核心思想相同:
- Closed (关闭):正常状态,允许请求通过。
- Open (打开):当失败率超过阈值,熔断器打开,直接拒绝所有请求,快速失败。
- Half-Open (半开):经过一段休眠时间后,熔断器进入半开状态,允许少量请求试探下游服务是否恢复。如果成功,则回到Closed状态;如果失败,则继续保持Open状态。
- 降级 (Fallback):当请求被熔断或超时时,执行一个预先定义好的降级逻辑,返回一个友好或默认的结果,保证用户体验不完全中断。
-
服务间通信:
- HTTP/REST:基于HTTP协议,使用JSON/XML交换数据。优点是简单、通用、跨语言。缺点是性能相对较低(文本解析、TCP连接开销)。
- RPC (Remote Procedure Call):
- 框架:Dubbo, gRPC, Apache Thrift。
- 优势:通常基于二进制协议(如Protobuf)和长连接(如Netty),性能远高于HTTP/REST。提供更强的服务治理能力(如负载均衡、服务发现、熔断)。
- gRPC:Google开源的高性能、跨语言的RPC框架,使用HTTP/2作为传输协议,Protobuf作为默认的接口定义语言(IDL)和消息序列化格式。
-
API 网关核心功能:
- 路由 (Routing):根据请求的路径、Header等信息,将请求转发到正确的后端微服务。
- 负载均衡 (Load Balancing):在多个服务实例间分配请求流量。
- 认证鉴权 (Authentication & Authorization):统一处理JWT、OAuth2等安全令牌的校验,确保请求的合法性。
- 限流 (Rate Limiting):防止某个客户端或服务滥用API,保护后端服务稳定。
- 熔断与降级 (Circuit Breaking & Fallback):保护后端服务,提高系统容错能力。
- 日志与监控 (Logging & Monitoring):记录所有请求日志,集成Prometheus、Zipkin等,便于问题排查和性能分析。
- 请求/响应转换:修改请求头、响应头,或对请求/响应体进行转换。

被折叠的 条评论
为什么被折叠?



