本文目录导读:

- 📖 目录导读
- 面试官到底在考什么?——框架原理的底层逻辑
- Spring IoC / AOP 源码级原理剖析(含高频面试题)
- Spring Boot 自动配置的“魔法”与面试陷阱
- MyBatis 动态代理与SQL注入防御案例分析
- Netty 线程模型与百万并发连接实战案例
- 分布式框架(Redis/ MQ)一致性面试必答点
- 经典大厂Java面试题问答(附答题话术)
- 结语:如何用“原理+案例”打动面试官
📖 目录导读
- 面试官到底在考什么?——框架原理的底层逻辑
- Spring IoC/ AOP 源码级原理剖析(含高频面试题)
- Spring Boot 自动配置的“魔法”与面试陷阱
- MyBatis 动态代理与SQL注入防御案例分析
- Netty 线程模型与百万并发连接实战案例
- 分布式框架(Redis/ MQ)一致性面试必答点
- 经典大厂Java面试题问答(附答题话术)
- 如何用“原理+案例”打动面试官
面试官到底在考什么?——框架原理的底层逻辑
很多Java开发者面试时死在“会用但说不清”上,面试官问“Spring Bean的生命周期”并不是为了背答案,而是想确认你是否理解对象创建、依赖注入、初始化、销毁这四条主线背后的扩展点设计。
核心观点: 原理面试 = 源码层级理解 + 设计模式识别 + 场景问题解决能力,凡是让你“说说原理”的题,本质上是在考你阅读源码和抽象建模的能力。
Spring IoC / AOP 源码级原理剖析(含高频面试题)
1 IoC容器启动流程(精简路径)
AnnotationConfigApplicationContext → refresh() → BeanFactoryPostProcessor → BeanPostProcessor → 实例化 → 属性填充 → 初始化(InitializingBean / @PostConstruct)→ AOP代理生成。
关键源码点:DefaultListableBeanFactory 的 getBean() 方法中,doGetBean 处理单例、原型、循环依赖(三级缓存)。
2 AOP代理原理
- JDK动态代理:基于接口,
Proxy.newProxyInstance()+InvocationHandler。 - CGLIB代理:继承目标类,生成子类字节码,通过
MethodInterceptor。
追问高频题:
- “为什么JDK代理只能针对接口?” → 因为
Proxy类生成的目标代理类已经extends Proxy,Java单继承限制。 - “Spring AOP和AspectJ有什么区别?” → Spring AOP是运行时增强(动态代理),AspectJ是编译期/加载期织入(静态)。
3 案例:事务失效
@Transactional
public void outer() {
this.inner(); // 内部自调用,代理失效!
}
原理:this.inner() 走的是this普通方法调用,不是代理对象,导致事务注解不生效,解决方案:注入自身代理,或拆开类。
Spring Boot 自动配置的“魔法”与面试陷阱
原理核心:@SpringBootApplication → @EnableAutoConfiguration → AutoConfigurationImportSelector → 读取 META-INF/spring.factories 中所有 AutoConfiguration 类。
条件装配:@ConditionalOnClass、@ConditionalOnMissingBean、@ConditionalOnProperty。
面试必答题:“如何自定义一个Starter?”
- 创建
@Configuration类,装配你的Bean。 - 在
META-INF/spring.factories中注册。 - 通过
@ConditionalOnMissingBean允许用户覆盖。
陷阱案例:项目里改了配置文件端口却不变——因为@ConditionalOnProperty匹配顺序有误,或者@Value注入时机不对。
MyBatis 动态代理与SQL注入防御案例分析
1 Mapper接口为什么没有实现类?
MyBatis通过 MapperProxyFactory 生成 MapperProxy(JDK动态代理),利用 @Select / @Insert 注解或XML里的MappedStatement,将方法调用转换为SQL执行。
2 SQL注入防御原理
- :直接文本替换 → 危险。
- :预编译占位符,底层用
PreparedStatement→ 安全。
案例:一个用户登录接口,如果错误使用拼接用户名,攻击者输入 ' or '1'='1 即可绕过密码验证,而能将参数当作字符串值,彻底杜绝拼接。
Netty 线程模型与百万并发连接实战案例
Reactor模型:主从多线程模型。
- Boss线程:Accept连接,注册到Worker。
- Worker线程:处理Read/Write及业务(默认
2*CPU核数)。
核心组件:EventLoop(事件循环)、ChannelPipeline(责任链)、ByteBuf(池化+引用计数)。
源码关键点:NioEventLoop内部组合了Selector,每1秒执行一次selectedKeys处理IO事件。
实战案例:设计IM服务,需要支撑百万长连接,底层关键是不能用阻塞IO,而是通过epoll + ChannelOption.SO_BACKLOG调优,若你在面试中说出“eventLoop线程数不要设置过大,避免上下文切换”以及“通过epoll多路复用解决C10K问题”,面试官立刻眼前一亮。
分布式框架(Redis/ MQ)一致性面试必答点
1 Redis缓存一致性问题(Cache Aside Pattern)
删除缓存 + 更新DB的顺序错误会导致脏数据。 正确思路:先更新DB,再删除缓存,但在并发场景下可能短暂旧值,面试要答出“延迟双删”或“版本号(乐观锁)方案”。
2 MQ消息可靠性与幂等性
- 生产端:
confirm确认机制。 - 消费端:手动
ack+ 重试机制。 - 幂等性:通过
messageId去重表或RedisSETNX。
问答示例: “为什么不能先发MQ再更新数据库?” → 若MQ发送成功但DB更新失败,则消息为无效消息,应保证最终一致性,使用本地消息表或事务消息。
经典大厂Java面试题问答(附答题话术)
问题1:BeanFactory 和 FactoryBean 的区别?
- 答案:
FactoryBean是一个接口,当它的getObject()返回值注入容器时,你得到的是该方法的返回值,而不是FactoryBean本身,在Spring中,若想控制Bean创建过程(如代理、初始化),就实现FactoryBean,答题时要强调“一个是容器,一个是生产Bean的工厂模式”。
问题2:如何设计一个不超卖的秒杀系统?
- 答案:前端限流 → 后端Redis预减库存(Lua脚本保证原子性) → MQ异步下单 → DB扣减库存,关键点在于“库存操作必须原子化”,并在落库时用
UPDATE ... WHERE stock > 0做最终校验。
问题3:堆外内存如何避免OOM?
- 答案:使用
DirectByteBuffer,启动参数设置-XX:MaxDirectMemorySize,排查时用jcmd或arthas监控DirectBufferMemory,注意零拷贝(FileChannel.transferTo)是高效方案,但需手动释放。
如何用“原理+案例”打动面试官
面试高分公式:一句话原理定义 + 一个源码关键点 + 一个真实业务案例。
不要只背“IoC是控制反转”,而要说出“它如何通过三级缓存解决循环依赖”,遇到框架问题时,先画生命周期图或请求流程图,再描述异常场景(如缓存击穿、代理失效),最后给出代码级解决方案,这就是顶级程序员和CRUD工程师的本质区别。
最后提醒:每一场面试前,亲自把SpringBoot启动过程,以及Netty的bind到accept的连接时序,用多线程模型画一遍,画图是检验理解程度的最好方式,祝你拿Offer到手软。