面试官与谢飞机的Java大厂面试对决:从Spring Boot到微服务架构
面试官与谢飞机的Java大厂面试对决:从Spring Boot到微服务架构
场景:某互联网大厂会议室,阳光透过百叶窗洒在长桌上。一位表情严肃、戴着眼镜的面试官(简称“面”)正翻看着简历,对面坐着的是自称“全栈通”的求职者——谢飞机(简称“谢”),他穿着格子衫,头发略显凌乱,眼神中透着一丝紧张和自信交织的光芒。
第一轮:基础不牢,地动山摇?
面:谢先生,请介绍一下你在项目中使用 Spring Boot 的经验。
谢:当然!我用过 Spring Boot 做过用户中心系统,整合了 MyBatis 和 Redis,还用了 Swagger 生成 API 文档。
面:很好。那你说说,Spring Boot 自动装配是怎么实现的?
谢:这个……就是 @SpringBootApplication 注解,它包含了 @EnableAutoConfiguration,然后 Spring 就会自动加载配置类。
面:嗯,那这些配置类是从哪来的?
谢:应该是从 META-INF/spring.factories 文件里读的吧?我记得有个 key 叫 org.springframework.boot.autoconfigure.EnableAutoConfiguration。
面:不错,看来你看过源码。那你来说说,如果我想自定义一个 Starter,该怎么做?
谢:呃……建个 Maven 工程,写个配置类,再在 spring.factories 里注册一下就行了吧?
面:基本思路是对的。不过要注意条件装配,比如 @ConditionalOnClass、@ConditionalOnMissingBean,这样才能避免冲突。
谢:哦对对对,条件注解我也用过!
面:很好,继续下一个问题。
第二轮:进阶挑战,水货现形?
面:假设我们现在要做一个电商秒杀系统,你会如何设计缓存层?
谢:用 Redis 啊!把商品信息、库存都放进去,速度快。
面:如果缓存雪崩了怎么办?
谢:雪崩?就是很多 key 同时失效吗?那我可以给不同的 key 设置随机过期时间,比如基础时间加上 0~300 秒的随机值。
面:还可以呢?
谢:嗯……可以用多级缓存,本地缓存加 Redis,这样即使 Redis 挂了,还有本地兜底。
面:那缓存穿透呢?
谢:穿透?就是查不到的数据一直打到数据库?那我可以用布隆过滤器提前拦截无效请求!
面:很好。那如果布隆过滤器误判了怎么办?或者数据更新后怎么同步?
谢:这……一般不会误判吧?至于更新,我可以让服务在更新数据库的同时,也更新缓存……
面:那你有没有考虑过双写一致性问题?
谢:双写?应该……问题不大吧?
面:……
第三轮:微服务风云,谁能笑到最后?
面:现在系统要拆分成微服务架构,订单、用户、商品各自独立部署。订单服务调用用户服务获取用户信息,你怎么保证调用的稳定性?
谢:用 OpenFeign 调用呗,简单方便。
面:如果用户服务响应慢或者宕机了呢?
谢:那……订单就失败呗。
面:用户体验很差。有没有更好的方案?
谢:可以加个超时设置!Feign 支持设置连接和读取超时。
面:还不够。我们希望即使下游服务不可用,也能返回降级数据。
谢:降级?是不是可以用 Hystrix?我记得它可以做熔断和降级。
面:Hystrix 已经停更了,现在主流是什么?
谢:啊?那……Sentinel?Resilience4j?我听说过,但没用过……
面:Resilience4j 是基于函数式编程的轻量级容错库,适合 Spring Boot 微服务。你可以结合 OpenFeign 使用,通过切面或装饰器实现重试、熔断、限流。
谢:原来如此!学到了学到了!
面:今天的面试就到这里。你的基础知识还算扎实,但在高并发、分布式系统的设计上还需要加强。我们会综合评估,后续 HR 会通知你结果。
谢:好的好的,谢谢面试官!我回去一定好好学习!
(谢飞机走出会议室,长舒一口气,掏出手机打开“牛客网”,搜索:“Resilience4j 实战教程”……)
【附录】面试题解析与技术深度剖析
一、Spring Boot 自动装配原理
1. 核心机制
Spring Boot 的自动装配依赖于以下三个核心注解:
@SpringBootConfiguration:标记为主配置类@EnableAutoConfiguration:启用自动配置@ComponentScan:扫描组件
其中最关键的是 @EnableAutoConfiguration,它通过 @Import(AutoConfigurationImportSelector.class) 导入了一组自动配置类。
2. 加载流程
- Spring Boot 启动时,
AutoConfigurationImportSelector会去所有 jar 包下的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(新版本)或spring.factories(旧版本)文件中查找自动配置类。 - 这些配置类通常带有
@ConditionalOnXxx条件注解,只有满足条件才会被加载。 - 例如
DataSourceAutoConfiguration会在 classpath 中存在DataSource类且没有用户自定义的DataSourceBean 时才生效。
3. 自定义 Starter 示例
// 配置类
@Configuration
@ConditionalOnClass(RedisTemplate.class)
@EnableConfigurationProperties(RedisProperties.class)
public class CustomRedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(RedisTemplate.class)
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 设置序列化方式等
return template;
}
}
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.starter.CustomRedisAutoConfiguration
二、电商秒杀系统的缓存设计
1. 缓存雪崩
问题:大量缓存同时失效,导致请求直接打到数据库。
解决方案:
- 随机过期时间:
expireTime + random(0~300s) - 多级缓存:Caffeine(本地) + Redis(分布式)
- 缓存预热:系统启动时主动加载热点数据
2. 缓存穿透
问题:查询不存在的数据,缓存不命中,请求直达 DB。
解决方案:
- 布隆过滤器:快速判断 key 是否可能存在
- 缓存空值:对查询结果为空的 key 也缓存一段时间(注意设置较短 TTL)
3. 缓存击穿
问题:某个热点 key 失效瞬间,大量并发请求击穿缓存。
解决方案:
- 互斥锁:使用
SETNX或 Redisson 分布式锁重建缓存 - 永不过期:后台异步更新缓存,前台始终返回旧值
4. 双写一致性
问题:数据库和缓存同时更新时可能出现不一致。
常用策略:
- 先更新数据库,再删除缓存(Cache Aside Pattern)
- 延迟双删:更新 DB → 删除缓存 → 延迟几百毫秒 → 再次删除缓存
- 使用 Canal 监听 MySQL binlog,异步更新缓存
三、微服务调用的稳定性保障 —— Resilience4j
1. 核心组件
- CircuitBreaker(熔断器):防止雪崩,自动隔离故障服务
- RateLimiter(限流器):控制每秒请求数
- Retry:自动重试失败请求
- Bulkhead(舱壁):限制并发数,防止资源耗尽
- TimeLimiter:设定调用超时时间
2. 与 OpenFeign 集成示例
resilience4j.circuitbreaker.instances.user-service.failure-rate-threshold=50
resilience4j.circuitbreaker.instances.user-service.minimum-number-of-calls=10
resilience4j.retry.instances.user-service.max-attempts=3
@FeignClient(name = "user-service", fallback = UserFallback.class)
public interface UserClient {
@GetMapping("/users/{id}")
User findById(@PathVariable("id") Long id);
}
@Component
public class UserFallback implements UserClient {
@Override
public User findById(Long id) {
return new User(id, "默认用户", "offline");
}
}
3. 熔断状态机
- CLOSED:正常调用,统计失败率
- OPEN:达到阈值,拒绝所有请求
- HALF_OPEN:冷却时间后尝试恢复,成功则 CLOSED,失败则继续 OPEN
结语:一场面试,既是技术的较量,也是成长的契机。谢飞机虽然暴露了知识盲区,但他愿意学习的态度值得肯定。而作为开发者,我们应不断深入底层原理,理解设计思想,才能在复杂业务场景中游刃有余。
更多推荐



所有评论(0)