【面试】框架常见面试(追问)
1. Spring IOC 容器的原理是什么?
例子:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) context.getBean("userService");
场景:通过 IoC 容器管理对象生命周期,避免手动 new 对象。
解决方法:基于 反射 + 配置(XML/注解),实现对象解耦。
追问链条:
问:IoC 容器是怎么注入依赖的?
答:依赖查找(DL)或依赖注入(DI),常用构造函数注入 / setter 注入。问:@Autowired 默认是按什么方式注入的?
答:默认按类型注入,如果有多个实现,再按名称匹配。问:如果有多个同类型 Bean 怎么解决冲突?
答:用@Primary
或@Qualifier
指定。
2. Spring AOP 的实现原理?
例子:
@Aspect public class LogAspect { @Before("execution(* com.example.service.*.*(..))") public void before() { System.out.println("before method..."); } }
场景:日志、事务、权限校验等横切逻辑。
解决方法:基于 动态代理(JDK / CGLIB)。
追问链条:
问:JDK 动态代理和 CGLIB 有什么区别?
答:JDK 只能代理接口,CGLIB 基于继承,可以代理类。问:Spring 如何选择代理方式?
答:默认优先 JDK 动态代理,若没有接口则用 CGLIB。问:AOP 是运行时还是编译时织入?
答:Spring AOP 是运行时,AspectJ 可以编译时。
3. Spring 中的事务传播行为有哪些?
例子:
@Transactional(propagation = Propagation.REQUIRED) public void addUser() {}
场景:控制方法嵌套调用时事务的传播方式。
解决方法:合理选择
REQUIRED
/REQUIRES_NEW
/NESTED
等。追问链条:
问:REQUIRED 和 REQUIRES_NEW 的区别?
答:REQUIRED 复用外部事务,REQUIRES_NEW 会新开事务并挂起外部事务。问:NESTED 和 REQUIRES_NEW 有什么不同?
答:NESTED 用保存点回滚,不会挂起外部事务。问:只读事务有什么用?
答:告诉数据库优化器不需要写锁,减少开销。
4. Spring Boot 自动装配原理?
例子:
@SpringBootApplication
会触发自动装配。场景:免去繁琐的 XML 配置。
解决方法:基于
@EnableAutoConfiguration
+spring.factories
。追问链条:
问:自动装配是怎么生效的?
答:通过SpringFactoriesLoader
读取类路径下的配置,反射加载。问:如何排除不需要的自动装配?
答:@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
。问:和 Spring XML 配置的区别?
答:Boot 提供约定优于配置,能快速启动项目。
5. Spring MVC 的执行流程?
例子:访问
/user/list
→ DispatcherServlet → HandlerMapping → Controller → ViewResolver → 页面渲染。场景:前后端交互请求处理。
解决方法:基于前端控制器模式。
追问链条:
问:DispatcherServlet 的作用?
答:前端控制器,统一分发请求。问:拦截器和过滤器区别?
答:过滤器是 Servlet 规范,拦截器是 Spring MVC 提供的,更细粒度。问:返回 JSON 是怎么实现的?
答:依赖HttpMessageConverter
,常用 Jackson。
6. MyBatis 和 Hibernate 的区别?
例子:
MyBatis:写 SQL → XML 映射
Hibernate:HQL / Criteria,自动生成 SQL
场景:持久层框架选择。
解决方法:业务复杂 SQL 多用 MyBatis;快速开发用 Hibernate。
追问链条:
问:MyBatis 优势是什么?
答:灵活、性能高、可控 SQL。问:Hibernate 的优势?
答:对象关系映射强,开发效率高。问:为什么很多公司用 MyBatis?
答:大部分项目需要灵活 SQL 调优,而 Hibernate 封装过重。
7. MyBatis 的一级缓存和二级缓存?
例子:
User u1 = session.selectOne("getUser", 1); User u2 = session.selectOne("getUser", 1);
场景:缓存查询结果减少数据库访问。
解决方法:合理利用缓存,避免脏数据。
追问链条:
问:一级缓存作用域?
答:SqlSession 级别,默认开启。问:二级缓存作用域?
答:Mapper 级别,可跨 SqlSession。问:缓存不一致怎么解决?
答:update/delete 操作会清除对应缓存。
8. Spring Cloud 和 Dubbo 的区别?
例子:Spring Cloud(全家桶)、Dubbo(RPC 框架)。
场景:微服务架构技术选型。
解决方法:Cloud 适合全套生态,Dubbo 偏向 RPC 高性能调用。
追问链条:
问:Dubbo 注册中心能用 Nacos 吗?
答:可以,支持多种注册中心。问:Spring Cloud 如何做服务发现?
答:依赖 Eureka、Consul、Nacos 等。问:Dubbo 和 gRPC 的区别?
答:Dubbo 偏 Java 生态,gRPC 跨语言。
9. Spring Bean 的生命周期?
例子:实例化 → 属性赋值 → 初始化 → 使用 → 销毁。
场景:掌握 Bean 生命周期,方便扩展。
解决方法:实现
InitializingBean
、DisposableBean
,或用@PostConstruct
。追问链条:
问:BeanFactory 和 ApplicationContext 区别?
答:BeanFactory 延迟加载,ApplicationContext 启动时加载。问:单例 Bean 和原型 Bean 生命周期不同?
答:原型 Bean 每次获取都会创建。问:BeanPostProcessor 有什么用?
答:在初始化前后做扩展,比如 AOP。
10. Spring Cloud 中的熔断机制?
例子:Hystrix 或 Resilience4j。
场景:防止下游服务故障导致雪崩。
解决方法:配置熔断器、线程池隔离、fallback 降级逻辑。
追问链条:
问:熔断和限流区别?
答:熔断是被动保护,限流是主动控制流量。问:Hystrix 为什么被替换?
答:社区停止维护,Spring Cloud 推荐 Resilience4j。问:熔断和重试能一起用吗?
答:可以,但要避免放大压力。
11. Spring 中的循环依赖是怎么解决的?
例子:
A
依赖B
,B
依赖A
。场景:单例 Bean 循环依赖。
解决方法:Spring 三级缓存(singletonFactories、earlySingletonObjects、singletonObjects)。
追问链条:
问:构造器注入会不会导致循环依赖?
答:会,Spring 无法解决,只能抛异常。问:为什么 setter 注入可以解决?
答:因为对象先实例化再注入属性,可以提前暴露引用。问:@Lazy 能解决循环依赖吗?
答:可以,延迟加载避免启动时立即依赖。
12. Spring Boot 如何实现外部配置加载?
例子:
application.properties
/application.yml
。场景:不同环境下的配置管理。
解决方法:基于
Environment
和PropertySource
抽象。追问链条:
问:配置加载的优先级?
答:命令行参数 > application.yml > 环境变量 > 默认值。问:如何在代码中获取配置?
答:@Value
注入,或用Environment
。问:Spring Cloud Config 如何实现集中配置?
答:从 Git 仓库或配置中心统一拉取。
13. Spring Security 的过滤器链?
例子:
UsernamePasswordAuthenticationFilter
处理表单登录。场景:用户认证和权限控制。
解决方法:基于
FilterChainProxy
,顺序执行安全过滤器。追问链条:
问:和普通 Servlet Filter 的区别?
答:Security 的过滤器链更细粒度,按安全逻辑排列。问:怎么自定义认证逻辑?
答:实现AuthenticationProvider
。问:如何实现 URL 级别的权限控制?
答:配置HttpSecurity
的antMatchers().hasRole()
。
14. Spring Data JPA 和 MyBatis 的区别?
例子:
JPA:
userRepository.findByName("Tom")
MyBatis:
<select id="getUser"> SELECT * FROM user WHERE name=#{name} </select>
场景:ORM 框架选择。
解决方法:SQL 灵活度高的用 MyBatis;快速开发用 JPA。
追问链条:
问:JPA 的优势?
答:自动生成 SQL,开发效率高。问:MyBatis 的优势?
答:SQL 可控、性能更稳定。问:能否结合使用?
答:可以,常见于混合架构。
15. Spring Cloud Gateway 和 Zuul 区别?
例子:Spring Cloud Gateway 基于 Netty,Zuul 1 基于 Servlet。
场景:微服务网关。
解决方法:新项目优先选 Spring Cloud Gateway。
追问链条:
问:为什么 Zuul 1 性能差?
答:基于阻塞 I/O,单线程处理。问:Gateway 如何实现路由?
答:基于 Reactor Netty + WebFlux。问:Zuul 2 和 Gateway 谁更好?
答:Gateway 社区更活跃,集成 Spring Cloud 更方便。
16. MyBatis 的动态 SQL 怎么实现?
例子:
<if test="name != null">AND name = #{name} </if>
场景:条件查询时灵活拼接 SQL。
解决方法:基于 OGNL 表达式解析 XML 标签。
追问链条:
问:choose/when/otherwise 的作用?
答:类似 switch-case。问:foreach 用来做什么?
答:批量查询/插入。问:动态 SQL 的性能会不会差?
答:不会,MyBatis 会缓存编译后的 SQL。
17. Spring Boot Starter 原理?
例子:
spring-boot-starter-web
引入 Web 依赖。场景:模块化依赖管理。
解决方法:基于
spring.factories
定义自动配置类。追问链条:
问:如何自定义 Starter?
答:定义 AutoConfiguration 类并注册到spring.factories
。问:Starter 和普通依赖区别?
答:Starter 包含自动配置,普通依赖只是库。问:为什么 Starter 叫“起步依赖”?
答:能快速搭建项目基础功能。
18. Spring 事务失效的场景?
例子:同类方法调用
this.method()
,事务不会生效。场景:代理机制导致事务未织入。
解决方法:确保调用经过 Spring AOP 代理。
追问链条:
问:为什么 self-invocation 不生效?
答:因为方法调用没经过代理对象。问:@Transactional 标注在 private 方法上能生效吗?
答:不能,只能在 public 方法上生效。问:怎么解决 self-invocation 问题?
答:通过 ApplicationContext 获取代理对象调用。
19. Spring Cloud Eureka 的原理?
例子:服务注册到 Eureka Server。
场景:微服务的注册发现。
解决方法:基于心跳机制和自我保护模式。
追问链条:
问:什么是自我保护模式?
答:网络分区时,Eureka 保留已注册服务,避免误删。问:和 Zookeeper 对比?
答:Zookeeper 强一致,Eureka 追求可用性。问:Eureka 为什么逐渐被 Nacos 替代?
答:Nacos 支持配置中心 + 注册中心,功能更全。
20. Spring Cloud Feign 的实现原理?
例子:
@FeignClient(name="user-service") public interface UserClient {@GetMapping("/user/{id}")User getUser(@PathVariable Long id); }
场景:声明式 HTTP 调用。
解决方法:基于 JDK 动态代理 + Ribbon/LoadBalancerClient。
追问链条:
问:Feign 和 RestTemplate 的区别?
答:Feign 声明式,RestTemplate 手写。问:如何启用 Feign 日志?
答:配置logging.level.feign=DEBUG
。问:Feign 超时如何配置?
答:通过feign.client.config
设置。
21. Netty 为什么比 BIO/NIO 更高效?
例子:聊天服务器用 Netty,比 BIO Socket 高效。
场景:高并发网络通信。
解决方法:基于 Reactor 模型 + 零拷贝。
追问链条:
问:Netty 的线程模型是什么?
答:BossGroup 接收连接,WorkerGroup 处理读写。问:什么是零拷贝?
答:减少内核态和用户态的数据复制。问:和 Tomcat 的 NIO Connector 对比?
答:Netty 更灵活,支持 TCP/UDP/自定义协议。
22. Spring WebFlux 和 Spring MVC 区别?
例子:WebFlux 用 Reactor Mono/Flux,MVC 用 Servlet。
场景:响应式编程 vs 阻塞式编程。
解决方法:高并发 IO 密集用 WebFlux;普通应用用 MVC。
追问链条:
问:WebFlux 底层基于什么?
答:Reactor + Netty。问:能和 Spring MVC 共存吗?
答:可以,不同 DispatcherServlet。问:WebFlux 对 CPU 密集任务有没有帮助?
答:没有,适合 IO 密集。
23. Spring Cloud Config 的原理?
例子:配置从 Git 仓库拉取。
场景:集中化配置管理。
解决方法:基于
EnvironmentRepository
和@RefreshScope
。追问链条:
问:@RefreshScope 怎么生效?
答:通过 Actuator/refresh
或 Bus 触发。问:如果 Git 不可用怎么办?
答:可以用本地配置或 Nacos 替代。问:和 Apollo 区别?
答:Apollo 实时推送,Config 拉模式。
24. Spring Batch 的使用场景?
例子:定时导入 CSV 数据到数据库。
场景:批处理任务。
解决方法:基于 Step/Job/Tasklet。
追问链条:
问:Spring Batch 如何保证幂等?
答:通过 JobInstance + JobExecution。问:能否结合 Quartz?
答:可以,用 Quartz 定时触发 Batch Job。问:和普通循环插入区别?
答:Batch 内置事务、并行、容错。
25. Netty 的粘包/拆包问题?
例子:TCP 流数据可能粘连。
场景:网络通信中消息边界不明确。
解决方法:使用 LengthFieldBasedFrameDecoder。
追问链条:
问:为什么 TCP 会粘包?
答:因为是字节流协议,没有边界。问:常见解决方案?
答:固定长度、分隔符、长度字段。问:Netty 内置哪些解码器?
答:LineBasedFrameDecoder、DelimiterBasedFrameDecoder 等。
26. Spring Actuator 的作用?
例子:访问
/actuator/health
查看健康状态。场景:应用监控。
解决方法:开启 Actuator 并暴露端点。
追问链条:
问:默认暴露哪些端点?
答:health、info。问:如何自定义健康检查?
答:实现HealthIndicator
。问:和 Prometheus 怎么集成?
答:通过/actuator/prometheus
端点。
27. Spring Bean 的作用域?
例子:
@Scope("prototype")
。场景:控制 Bean 实例化方式。
解决方法:常见作用域有 singleton、prototype、request、session。
追问链条:
问:默认作用域是什么?
答:singleton。问:prototype Bean 如何销毁?
答:容器不负责,需手动管理。问:request/session 作用域适合什么场景?
答:Web 应用请求级、会话级对象。
28. Spring Cloud Sleuth 的作用?
例子:分布式链路追踪。
场景:微服务调用链跟踪。
解决方法:基于 TraceId、SpanId。
追问链条:
问:和 Zipkin 关系?
答:Sleuth 负责生成追踪数据,Zipkin 收集展示。问:和 SkyWalking 区别?
答:SkyWalking 功能更强,支持多语言。问:追踪数据存储在哪?
答:可以存 ES、MySQL、Kafka。
29. Spring Cloud Stream 的作用?
例子:基于 RabbitMQ/Kafka 的消息驱动。
场景:解耦消息中间件实现。
解决方法:用
@StreamListener
/@EnableBinding
。追问链条:
问:如何实现生产者/消费者?
答:定义输入输出通道绑定 MQ。问:消息顺序怎么保证?
答:分区绑定。问:和直接用 Kafka API 区别?
答:Stream 屏蔽底层差异,更加解耦。
30. Spring Boot 如何实现异步任务?
例子:
@Async public void sendEmail() {}
场景:异步执行耗时操作。
解决方法:启用
@EnableAsync
,配置线程池。追问链条:
问:@Async 默认用什么线程池?
答:SimpleAsyncTaskExecutor,不推荐生产用。问:如何自定义线程池?
答:定义ThreadPoolTaskExecutor
Bean。问:异步方法调用自身会生效吗?
答:不会,同事务问题一样,需要代理对象调用。