⚙️ Spring 核心架构概览
在深入具体的 Spring原理框架面试 细节之前,我们需要建立全局视角。Spring 框架并非单一的工具库,而是一个分层的应用程序框架。其核心模块包括 Spring Core(核心容器)、Spring Context(上下文抽象)、Spring AOP(面向切面编程)、Spring DAO(数据访问)以及 Spring Web(Web应用支持)。
面试官在考察 Spring原理框架面试 相关知识点时,通常希望候选人能够清晰地阐述这些模块之间的依赖关系,以及如何通过 Spring 的依赖注入(DI)机制将各个模块有机地结合起来,形成松耦合的企业级应用架构。
| 模块名称 | 核心功能 | 面试考察频率 |
|---|---|---|
| Spring Core | 提供 IOC 容器和依赖注入机制 | ⭐⭐⭐⭐⭐ |
| Spring AOP | 实现事务管理、日志记录等横切关注点 | ⭐⭐⭐⭐⭐ |
| Spring MVC | Web层框架,处理请求映射与视图解析 | ⭐⭐⭐⭐ |
| Spring Data | 简化数据库访问,支持多种持久化框架 | ⭐⭐⭐ |
| Spring Boot | 自动配置、起步依赖,简化Spring应用搭建 | ⭐⭐⭐⭐⭐ |
⚡ IOC 容器与 DI 机制源码解析
控制反转(Inversion of Control, IOC) 和 依赖注入(Dependency Injection, DI) 是 Spring 框架的基石。在 Spring原理框架面试 中,面试官常问:“请描述一下 Spring IOC 容器的启动过程?”
1. IOC 容器启动流程
当 Spring 应用启动时,ApplicationContext 的实现类(如 AnnotationConfigApplicationContext)会执行以下步骤:
- 资源定位:通过
ResourceLoader加载配置文件或扫描注解类。 - Bean 定义注册:将解析后的
BeanDefinition注册到BeanDefinitionRegistry中。 - Bean 实例化:调用
BeanFactoryPostProcessor对 Bean 定义进行后处理(如解析占位符)。 - 依赖注入:实例化单例 Bean,填充属性,执行
BeanPostProcessor的前置和后置处理。
2. 循环依赖解决方案
在 Spring原理框架面试 中,循环依赖是一个高频考点。Spring 通过“三级缓存”机制解决了单例 Bean 的循环依赖问题:
- 一级缓存(singletonObjects):存放完全初始化好的 Bean。
- 二级缓存(earlySingletonObjects):存放早期的 Bean 对象(已实例化但未属性填充)。
- 三级缓存(singletonFactories):存放 Bean 工厂,用于生成早期引用,主要解决 AOP 代理导致的循环依赖问题。
当 Bean A 依赖 Bean B,而 Bean B 又依赖 Bean A 时,Spring 会先实例化 A,将其工厂放入三级缓存,然后在属性填充时发现 B,实例化 B。B 填充属性时发现 A,从三级缓存获取 A 的早期引用(如果 A 需要 AOP 代理,则通过工厂生成代理对象放入二级缓存),完成 B 的初始化。最后 A 从二级缓存获取 B,完成自身初始化。
⚙️ AOP 动态代理原理
面向切面编程(AOP) 使得开发者能够将横切关注点(如日志、事务、安全)与业务逻辑分离。在 Spring原理框架面试 中,理解 AOP 的底层实现至关重要。
JDK 动态代理
JDK 动态代理是基于接口的。它要求目标类必须实现至少一个接口。底层通过 java.lang.reflect.Proxy 类和 InvocationHandler 接口实现。
// 示例代码片段
Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) {
// 前置处理
Object result = method.invoke(target, args);
// 后置处理
return result;
}
}
);
优点:无需额外依赖,JDK 原生支持。
缺点:只能代理接口方法,无法代理类方法。
CGLIB 动态代理
CGLIB(Code Generation Library)是基于继承的。它通过字节码技术生成目标类的子类,并重写父类方法来拦截调用。
// 示例:CGLIB 增强器
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetClass.class);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) {
// 前置处理
Object result = proxy.invokeSuper(obj, args);
// 后置处理
return result;
}
});
return enhancer.create();
优点:可以代理没有接口的类。
缺点:需要引入 CGLIB 依赖,性能略低于 JDK 代理(但在现代 JVM 中差距已很小),无法代理 final 类或 final 方法。
Spring 的代理策略
在 Spring 中,默认情况下:
- 如果目标类实现了接口,Spring 默认使用 JDK 动态代理。
- 如果目标类没有实现接口,Spring 自动切换到 CGLIB 动态代理。
你可以通过 @EnableAspectJAutoProxy(proxyTargetClass = true) 强制使用 CGLIB,或者在 Spring Boot 2.x 之后,默认倾向于使用 CGLIB 以提供更一致的行为。
⚡ Bean 生命周期全流程
Bean 的生命周期 是 Spring原理框架面试 中的经典问题。理解这一流程有助于深入掌握 Spring 的扩展点。
1. 实例化(Instantiation)
Spring 容器通过反射调用构造函数或工厂方法创建 Bean 的原始实例。此时,Bean 的属性尚未填充。
2. 属性赋值(Populate Bean)
Spring 将 Bean 定义中的属性值填充到实例中。这是依赖注入发生的地方。
3. 初始化(Initialization)
如果 Bean 实现了 BeanNameAware、BeanFactoryAware 等接口,会调用相应回调方法。接着执行 BeanPostProcessor.postProcessBeforeInitialization。如果定义了 init-method 或 @PostConstruct,则执行初始化逻辑。最后执行 BeanPostProcessor.postProcessAfterInitialization(AOP 代理通常在此阶段生成)。
4. 销毁(Destruction)
当容器关闭时,如果 Bean 实现了 DisposableBean 或定义了 destroy-method,则执行销毁逻辑。
⚙️ Spring Boot 自动配置原理
Spring Boot 的核心在于“约定优于配置”,其自动配置机制是 Spring原理框架面试 中现代 Java 开发部分的重点。
核心注解:@EnableAutoConfiguration
该注解通过 @Import(AutoConfigurationImportSelector.class) 导入自动配置类。它的工作原理如下:
- 读取配置:从
META-INF/spring.factories(Spring Boot 2.7 之前)或META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(Spring Boot 2.7+)文件中读取所有候选的自动配置类。 - 条件判断:使用
@ConditionalOnClass、@ConditionalOnMissingBean等条件注解进行筛选。只有当类路径下存在特定类,且用户未手动定义 Bean 时,自动配置才会生效。 - 注册 Bean:符合条件的配置类被加载到 Spring 容器中,从而自动装配相关的 Bean。
这种机制极大地简化了应用配置,使得开发者能够“开箱即用”。
⚡ 高频面试问答(Q&A)
| 问题 | 简要解答 |
|---|---|
| Spring 中的 Bean 是线程安全的吗? | 默认情况下,Spring 的 Bean 是单例的,且无状态,因此是线程安全的。如果有状态(如成员变量),则需要通过 ThreadLocal 或原型作用域来保证线程安全。 |
| 如何解释 Spring 中的 @Transactional 失效场景? | 1. 方法非 public;2. 类内部自调用;3. 数据库引擎不支持事务(如 MyISAM);4. 异常被 catch 吞掉未抛出。 |
| Spring MVC 的工作流程是什么? | 用户发送请求 → DispatcherServlet 接收 → HandlerMapping 找到处理器 → HandlerAdapter 执行 Controller → Controller 返回 ModelView → ViewResolver 解析视图 → 渲染响应。 |
| Spring 中如何避免死锁? | 1. 固定锁获取顺序;2. 使用超时机制(Lock.tryLock);3. 减少锁粒度;4. 避免嵌套锁。 |