医健数联 Java开发 二面 面经
1. 详细介绍一下你负责的项目,系统架构是怎么设计的?
答:
- 项目背景:介绍业务场景、用户规模、日活量、并发量等关键指标,说明团队规模和你的角色定位
- 技术架构: 接入层:Gateway网关统一入口,负责路由转发、限流、鉴权服务层:按业务拆分微服务,Feign做同步调用,MQ做异步通信,Nacos做注册中心和配置中心数据层:MySQL主从读写分离,Redis缓存,MQ削峰填谷
- 技术难点:重点说高并发优化(多级缓存、限流、异步)和分布式事务(MQ最终一致性)
- 监控运维:Skywalking链路追踪,ELK日志分析,Prometheus+Grafana监控告警
- 关键:每个技术选型要说清楚为什么这么选,有没有考虑过其他方案
2. MySQL的索引失效场景有哪些,如何优化慢查询?
答:七种索引失效场景:
- 索引列上使用函数:
WHERE YEAR(create_time) = 2024,改为范围查询BETWEEN '2024-01-01' AND '2024-12-31' - 隐式类型转换:varchar字段用数字查询,加引号保证类型一致
- LIKE以%开头:
LIKE '%张三'不走索引,改为LIKE '张三%'或用全文索引 - OR条件有字段无索引:确保OR两边都有索引,或改用UNION
- 联合索引不满足最左前缀:索引(a,b,c),查询必须包含a才能走索引
- 范围查询后的字段失效:索引(a,b,c),b用了范围查询,c不走索引,把范围字段放最后
- NOT/!=/<>否定条件:通常不走索引,改写为正向条件
慢查询优化步骤:
- 开启慢查询日志,设置阈值(如2秒)找出慢SQL
- EXPLAIN分析执行计划,重点看type(最好是ref/range)、key(使用的索引)、rows(扫描行数)、Extra(避免Using filesort和Using temporary)
- 优化方向:添加合适索引、覆盖索引减少回表、优化SQL避免子查询、分页用延迟关联、数据量大考虑分库分表
- 定期ANALYZE TABLE更新统计信息,OPTIMIZE TABLE整理碎片
3. Spring Bean的生命周期,循环依赖如何解决?
答:Bean生命周期四个阶段:
- 实例化:反射调用构造方法创建Bean实例
- 属性赋值:反射注入属性值,处理@Autowired、@Resource等注解
- 初始化:依次调用Aware接口方法 → BeanPostProcessor前置处理 → afterPropertiesSet/init-method → BeanPostProcessor后置处理(AOP代理在此创建)
- 销毁:容器关闭时调用destroy方法释放资源
循环依赖解决(三级缓存):
- 一级缓存singletonObjects:存放完整的Bean
- 二级缓存earlySingletonObjects:存放早期Bean引用(未完成属性填充)
- 三级缓存singletonFactories:存放Bean工厂
解决过程:创建A→实例化A→A的工厂放三级缓存→注入属性发现需要B→创建B→实例化B→B的工厂放三级缓存→注入属性发现需要A→从三级缓存获取A的工厂创建早期引用放二级缓存→注入给B→B完成放一级缓存→A注入B→A完成放一级缓存
注意:只能解决单例Bean的setter注入循环依赖,构造器注入和原型Bean的循环依赖无法解决
4. JVM垃圾回收算法,G1收集器的原理
答:四种垃圾回收算法:
- 标记-清除:标记后统一回收,简单但产生内存碎片,效率低
- 标记-复制:内存分两块,存活对象复制到另一块,无碎片但浪费内存,新生代使用(Eden:S0:S1 = 8:1:1)
- 标记-整理:存活对象向一端移动,无碎片不浪费内存,但移动对象需要STW,老年代使用
- 分代收集:新生代用复制算法,老年代用标记-整理,根据对象存活周期选择合适算法
G1收集器原理:
- 把堆划分为多个大小相等的Region,每个Region可以是Eden/Survivor/Old区
- 跟踪每个Region的回收价值,优先回收价值最大的Region(Garbage First的含义)
- 四个回收阶段:初始标记(STW,标记GC Roots直接关联对象)→ 并发标记(和应用并发,遍历对象图)→ 最终标记(STW,
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经
