经纬恒润 Java开发 二面 面经
Java后端开发二面题目(完整版)
1. 说说Spring Boot的自动装配原理是如何实现的?
答案:
核心机制:
@SpringBootApplication包含三个注解@EnableAutoConfiguration触发自动装配@Import(AutoConfigurationImportSelector.class)导入配置
装配流程:
- 读取
META-INF/spring.factories文件 - 加载所有
EnableAutoConfiguration配置类 - 根据
@Conditional条件注解过滤 - 将符合条件的Bean注册到容器
常见条件注解:
@ConditionalOnClass:类路径存在某个类@ConditionalOnMissingBean:容器中没有某个Bean@ConditionalOnProperty:配置文件有某个属性
自定义starter:
- 创建配置类加
@Configuration - 在
spring.factories中注册 - 使用条件注解控制加载
2. Redis的数据结构有哪些?分别适用什么场景?
答案:
String(字符串):
- 场景:缓存、计数器、分布式锁
- 命令:SET、GET、INCR、DECR
Hash(哈希):
- 场景:存储对象、购物车
- 命令:HSET、HGET、HMGET
- 优势:节省内存,部分更新
List(列表):
- 场景:消息队列、时间线、最新列表
- 命令:LPUSH、RPUSH、LPOP、RPOP
- 特点:有序、可重复
Set(集合):
- 场景:标签、共同好友、去重
- 命令:SADD、SMEMBERS、SINTER
- 特点:无序、不重复
ZSet(有序集合):
- 场景:排行榜、延迟队列
- 命令:ZADD、ZRANGE、ZRANK
- 特点:按score排序
其他类型:
- Bitmap:签到、布隆过滤器
- HyperLogLog:UV统计
- GEO:地理位置
- Stream:消息队列(5.0+)
3. 分布式事务有哪些解决方案?各有什么优缺点?
答案:
1. 2PC(两阶段提交)
- 准备阶段:协调者询问参与者
- 提交阶段:统一提交或回滚
- 缺点:同步阻塞、单点故障、数据不一致
2. 3PC(三阶段提交)
- 增加CanCommit阶段
- 超时机制
- 缺点:复杂度高
3. TCC(Try-Confirm-Cancel)
- Try:预留资源
- Confirm:确认提交
- Cancel:取消回滚
- 优点:性能好、无锁
- 缺点:业务侵入性强
4. 本地消息表
- 业务和消息在同一事务
- 定时扫描发送消息
- 优点:实现简单
- 缺点:依赖定时任务
5. 消息队列(最终一致性)
- 发送消息到MQ
- 消费者处理业务
- 优点:解耦、高性能
- 缺点:只能保证最终一致
6. Seata(推荐)
- AT模式:自动补偿
- TCC模式:手动补偿
- SAGA模式:长事务
- 优点:对业务侵入小
选型建议:
- 强一致性:TCC、Seata AT
- 最终一致性:消息队列
- 简单场景:本地消息表
4. JVM内存模型是怎样的?如何排查内存溢出问题?
答案:
内存区域:
线程共享:
- 堆(Heap):对象实例、数组
- 方法区(元空间):类信息、常量、静态变量
线程私有:
- 虚拟机栈:局部变量、方法调用
- 本地方法栈:Native方法
- 程序计数器:字节码行号
常见OOM:
1. 堆溢出(最常见)
- 原因:对象过多、内存泄漏
- 错误:
java.lang.OutOfMemoryError: Java heap space - 排查: jmap -heap pid查看堆使用jmap -dump:format=b,file=heap.hprof pid导出堆MAT工具分析dump文件
2. 栈溢出
- 原因:递归太深、线程过多
- 错误:
StackOverflowError - 解决:增加栈大小
-Xss
3. 元空间溢出
- 原因:类加载过多
- 错误:
OutOfMemoryError: Metaspace - 解决:增加元空间
-XX:MetaspaceSize
排查步骤:
- 查看GC日志:
-XX:+PrintGCDetails - 使用jstat监控:
jstat -gc pid 1000 - dump堆分析:找到占用内存最多的对象
- 分析代码:是否有内存泄漏
预防措施:
- 合理设置堆大小
- 及时释放资源
- 使用对象池
- 避免大对象
5. MySQL的事务隔离级别有哪些?如何解决幻读问题?
答案:
四种隔离级别:
1. 读未提交(Read Uncommitted)
- 可以读到未提交的数据
- 问题:脏读、不可重复读、幻读
2. 读已提交(Read Committed)
- 只能读到已提交的数据
- 问题:不可重复读、幻读
- Oracle默认级别
3. 可重复读(Repeatable Read)
- 同一事务内多次读取结果一致
- 问题:幻读
- MySQL默认级别
4. 串行化(Serializable)
- 完全串行执行
- 无并发问题,性能最差
并发问题:
- 脏读:读到未提交的数据
- 不可重复读:两次读取数据不一致
- 幻读:两次查询记录数不一致
MySQL如何解决幻读:
MVCC(多版本并发控制):
- 每行记录有隐藏字段:事务ID、回滚指针
- 读取时根据ReadView判断可见性
- 快照读不会产生幻读
Next-Key Lock(间隙锁):
- 锁定记录+间隙
- 防止其他事务插入
- 当前读(SELECT FOR UPDATE)使用
示例:
-- 事务A BEGIN; SELECT * FROM table WHERE id > 10 FOR UPDATE; -- 锁定id>10的记录和间隙,事务B无法插入 -- 事务B INSERT INTO table VALUES(15, ...); -- 阻塞
6. 如何设计一个秒杀系统?需要考虑哪些问题?
答案:
核心问题:
- 高并发:瞬间大量请求
- 超卖:库存扣减不一致
- 恶意请求:刷单、爬虫
架构设计:
前端优化:
- 按钮置灰,防止重复点击
- 验证码、滑块验证
- 静态资源CDN加速
接口层:
- Nginx限流:限制单IP请求频率
- 网关限流:令牌桶、漏桶算法
- 接口防刷
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经
