一、Spring IoC容器启动源码深度解析

在面试中,Spring IoC容器的启动流程是必问环节。面试官通常希望候选人能够清晰描述从配置文件加载到Bean实例化的全过程。Spring的核心在于其容器管理着Bean的生命周期,而这一切始于XmlWebApplicationContext或AnnotationConfigApplicationContext的实例化。

1. 资源定位 (Resource Loading)

容器首先通过ResourceLoader接口将配置文件(如XML或注解包路径)转换为Resource对象。这一步负责将物理资源抽象为Spring内部统一的资源描述符,支持classpath、file、url等多种协议。

2. BeanDefinition加载

解析Resource后,通过BeanDefinitionReader将配置信息解析为BeanDefinition对象。这些对象包含了类名、作用域、依赖关系等元数据,并被注册到BeanDefinitionRegistry中。

3. 容器刷新 (Refresh)

调用refresh()方法是核心。该方法触发了finishBeanFactoryInitialization(),开始预实例化单例Bean。这是容器启动最耗时的阶段,涉及大量的反射操作和依赖注入。

核心代码流程示意:

// 1. 初始化上下文
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 内部调用 refresh()
// AbstractApplicationContext.refresh()
// 3. 准备BeanFactory
prepareBeanFactory(beanFactory);
// 4. 后置处理,如处理@PostConstruct
invokeBeanFactoryPostProcessors(beanFactory);
// 5. 注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 6. 实例化非懒加载的单例Bean
finishBeanFactoryInitialization(beanFactory);

二、Spring AOP动态代理机制源码剖析

AOP(面向切面编程)是Spring的另一大支柱。面试常问:Spring如何选择JDK动态代理还是CGLIB代理?源码中,这一逻辑主要由DefaultAopProxyFactory决定。

代理类型 适用场景 底层实现 性能对比
JDK动态代理 目标对象实现了接口 java.lang.reflect.Proxy 首次创建较慢,调用较快
CGLIB代理 目标对象未实现接口 字节码生成技术 (Enhancer) 首次创建极慢,调用稍慢于JDK

源码关键类解析:

  • ProxyFactory: AOP的入口类,负责组装Advisor、TargetSource等信息,并决定代理策略。
  • JdkDynamicAopProxy: 实现JDK动态代理,核心方法是invoke(),在反射调用目标方法前后织入Advice。
  • CglibAopProxy: 实现CGLIB代理,通过创建目标类的子类来拦截方法调用。核心是DynamicAdvisedInterceptor。
  • AdvisorChain: 在代理方法执行前,计算需要执行的拦截器链(Interceptor Chain),这是AOP织入逻辑的核心。

三、Spring Bean生命周期源码详解

理解Bean的生命周期是掌握Spring源码的基石。从实例化到销毁,Spring提供了丰富的扩展点。源码中,AbstractAutowireCapableBeanFactory的doCreateBean()方法是生命周期管理的核心。

Step 1

实例化 (Instantiation)

通过BeanUtils.instantiateClass()创建Bean实例。此时Bean还是裸对象,属性未注入。

Step 2

属性填充 (Populate Bean)

调用populateBean(),处理@Autowired、@Value等注解,完成依赖注入。涉及AutowiredAnnotationBeanPostProcessor。

Step 3

初始化 (Initialization)

调用initializeBean()。依次执行:
1. BeanPostProcessor.postProcessBeforeInitialization (前置处理)
2. @PostConstruct 注解方法
3. InitializingBean.afterPropertiesSet 接口方法
4. 自定义 init-method
5. BeanPostProcessor.postProcessAfterInitialization (后置处理,AOP代理在此阶段生成)

Step 4

销毁 (Destruction)

容器关闭时,调用DisposableBean.destroy()或自定义 destroy-method。

四、Spring事务管理源码分析

Spring事务是基于AOP实现的。当方法上标注@Transactional时,Spring会为其生成一个代理对象,事务逻辑被织入代理方法中。

关键源码类:

  • TransactionInterceptor: 事务的拦截器。在invoke()方法中,调用TransactionAspectSupport.invokeWithinTransaction()。
  • PlatformTransactionManager: 事务管理器接口。Spring通过此接口抽象底层事务(JDBC、JTA等)。
  • TransactionSynchronizationManager: 线程绑定。利用ThreadLocal将Connection绑定到当前线程,确保事务中多次数据库操作使用同一连接。
  • DefaultTransactionDefinition: 默认事务属性定义,包含隔离级别、传播行为、超时时间等。

传播行为源码逻辑:

传播行为 源码常量 逻辑描述
REQUIRED PROPAGATION_REQUIRED 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。
REQUIRES_NEW PROPAGATION_REQUIRES_NEW 创建一个新事务,如果当前存在事务,则把当前事务挂起。
NESTED PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则执行与REQUIRED类似的操作。

五、Spring Boot自动装配源码揭秘

Spring Boot的核心在于“约定优于配置”。@SpringBootApplication注解中的@EnableAutoConfiguration是实现自动装配的关键。

自动装配流程:

  1. 入口: @EnableAutoConfiguration 通过 @Import(AutoConfigurationImportSelector.class) 导入选择器。
  2. 加载配置: AutoConfigurationImportSelector 调用 getCandidateConfigurations(),读取 META-INF/spring.factories 文件(Spring Boot 2.7+ 改为 org.springframework.boot.autoconfigure.AutoConfiguration.imports)。
  3. 过滤: 根据 @Conditional 注解(如 @ConditionalOnClass, @ConditionalOnMissingBean)过滤掉不满足条件的配置类。
  4. 注册: 将符合条件的BeanDefinition注册到容器中。

常见Conditional注解:

@ConditionalOnClass

当类路径下存在指定类时,才加载该配置。

@ConditionalOnMissingBean

当容器中不存在指定类型的Bean时,才加载该配置(支持依赖注入的默认实现)。

@ConditionalOnProperty

当配置文件中的属性值匹配时,才加载该配置。

六、网友们还关心:Spring周边技术热点

除了核心的IoC和AOP,Spring源码面试题汇总中,面试官越来越关注Spring与其他技术的结合,以及其在高并发场景下的表现。以下是网友们近期搜索热度较高的周边知识点:

1 Spring与MyBatis的整合原理 查看详情 →
2 Spring Cloud微服务架构源码 查看详情 →
3 Spring Security安全框架原理 查看详情 →
4 Spring异步编程 @Async 源码解析 查看详情 →
5 Spring循环依赖解决方案详解 查看详情 →

深度拓展:Spring循环依赖解决方案

循环依赖是Spring源码面试中的高频难点。Spring通过三级缓存解决了单例Bean的循环依赖问题。

  • 一级缓存 (singletonObjects): 存放完整的、可以使用的Bean。
  • 二级缓存 (earlySingletonObjects): 存放早期的、未完全初始化的Bean实例(可能尚未注入属性)。
  • 三级缓存 (singletonFactories): 存放Bean工厂(ObjectFactory),用于在需要时生成早期引用,特别是为了处理AOP代理。

当Bean A依赖Bean B,Bean B又依赖Bean A时,A实例化后将其工厂放入三级缓存。当A注入B时,发现B未创建,转而创建B。B实例化后注入A时,从三级缓存获取A的早期引用(若A有AOP,则通过工厂生成代理),完成B的创建。最后A完成属性注入和初始化。

七、学习建议与资源推荐

掌握Spring源码不仅需要阅读代码,更需要结合调试和实际应用场景。建议开发者:

1. 善用Debug

在关键断点处单步调试,观察Bean的创建过程和代理对象的生成。

2. 阅读官方文档

Spring官方文档提供了详细的架构介绍,是理解源码的指南针。

3. 关注社区动态

通过GitHub Issues和Stack Overflow了解常见问题的源码级解决方案。