Spring源码分析

IOC

BeanDefinition

BeanDefinition 是 Spring IoC 容器的基石,它是 Bean 的一切元数据(类名、作用域、构造函数参数、属性等)的载体,是面向接口编程思想的体现。容器操作的是 BeanDefinition,而非直接操作 Class

我们最常用的就是DefaultListableBeanFactorybeanDefinitionMap 这个 ConcurrentHashMap,所有加载的 BeanDefinition 都存储于此。

然后我们的IOC容器ApplicationContext 根据其实现(XML, Annotation)选择不同的策略(Reader, Scanner)来加载 BeanDefinition模板方法模式AbstractBeanDefinitionReader 等类中被广泛使用。

XML 路径: 从 AbstractXmlApplicationContext 的构造函数出发 -> loadBeanDefinitions(new XmlBeanDefinitionReader(this)) -> XmlBeanDefinitionReader.loadBeanDefinitions() -> doLoadDocument() (将XML转为DOM) -> registerBeanDefinitions() (解析DOM并注册 BeanDefinition)。

注解路径: 从 AnnotationConfigApplicationContext 构造函数出发 -> this.scanner.scan(...) -> ClassPathBeanDefinitionScanner.doScan() -> findCandidateComponents() (扫描路径,找到符合条件的类) -> isCandidateComponent() (检查是否包含 @Component 等注解) -> registerBeanDefinition()

IOC容器就是BeanFactory 是 IoC 容器的“核心引擎”,负责 Bean 的生命周期管理。而 ApplicationContext 是一个更高级的“企业级容器”,它继承了 BeanFactory 的所有功能,并在此基础上集成了AOP、事件发布、国际化等众多高级服务。

BeanFactory: 顶层接口,定义了 getBean() 等核心方法。

ListableBeanFactory: 扩展接口,提供枚举所有 Bean 的能力。

ConfigurableListableBeanFactory: BeanFactory 体系的终极接口,几乎包含了所有功能。

ApplicationContext: 继承了 ListableBeanFactory 和其他多个高级接口。

AbstractApplicationContext: 核心中的核心,其 refresh() 方法定义了容器启动的完整流程。

追踪AbstractApplicationContext.refresh() 方法

refresh()方法可以说是Spring IoC容器的“启动引擎”。它的核心使命就是根据我们的配置,创建并初始化一个功能完备的ApplicationContext,最终让所有Bean都准备就绪,随时可以被应用程序使用。

准备与定义加载

  1. prepareRefresh(): 做一些启动前的准备工作,比如设置启动时间、激活状态等。
  2. obtainFreshBeanFactory(): 这是奠定基础的一步。它会创建一个DefaultListableBeanFactory(IoC容器的底层核心),然后去解析我们的配置文件(无论是XML还是注解),把Bean的定义信息,也就是BeanDefinition,加载到容器中。需要强调的是,这个阶段只是加载了“蓝图”,还没有创建任何Bean的实例。
  3. prepareBeanFactory(): 对创建好的BeanFactory进行一些基础配置,比如设置类加载器、添加一些内置的后置处理器等。
  4. postProcessBeanFactory(): 这是一个模板方法,留给子类去扩展,体现了Spring设计的灵活性。

第二阶段:核心处理与扩展

这个阶段是refresh()的精髓所在,体现了Spring强大的扩展能力。这里有两个最重要的扩展点:

  1. invokeBeanFactoryPostProcessors(): 调用所有BeanFactoryPostProcessor。这个扩展点允许我们在所有Bean实例化之前,去修改Bean的定义信息(BeanDefinition)。比如,我们常用的${...}属性占位符替换,就是在这里完成的。@Configuration@ComponentScan等注解的解析也是由这个阶段的后置处理器完成的。
  2. registerBeanPostProcessors(): 注册所有BeanPostProcessor。这个扩展点则是在Bean实例化之后、初始化前后对Bean实例本身进行“加工”。Spring的AOP和声明式事务就是通过这个机制实现的。它会在这里为符合条件的Bean创建动态代理对象,对Bean实例进行增强。

第三阶段:实例化与完成

  1. initMessageSource()initApplicationEventMult-icaster(): 分别初始化国际化支持和事件广播器,为事件驱动模型做准备。
  2. onRefresh(): 又一个模板方法,像Spring Boot内嵌的Tomcat就是在这里启动的。
  3. registerListeners(): 把我们定义的事件监听器注册到事件广播器上。
  4. finishBeanFactoryInitialization(): 这是整个流程中最重量级的一步。Spring会在这里实例化所有非懒加载的单例Bean。这个过程包括了实例化、属性填充(依赖注入)、以及执行各种初始化回调,比如@PostConstructBeanPostProcessor的前后置处理方法。
  5. finishRefresh(): 所有工作完成后,它会发布一个ContextRefreshedEvent事件,通知应用程序容器已经准备就绪。

bean的生命周期

AbstractAutowireCapableBeanFactory: Bean 生命周期的主要执行者。

DefaultListableBeanFactory.preInstantiateSingletons() -> getBean() -> doGetBean()开始

AbstractAutowireCapableBeanFactory.createBean()包含以下扩展点:

resolveBeforeInstantiation(): 第一次扩展点,允许 InstantiationAwareBeanPostProcessor 返回一个代理对象,直接短路后续流程(AOP 早期代理化的机会)。

doCreateBean():

  • createBeanInstance(): 【实例化】 通过构造函数反射创建 Bean 的空对象。
  • populateBean(): 【属性填充】 依赖注入发生于此。会调用 InstantiationAwareBeanPostProcessorpostProcessProperties() 方法。
  • initializeBean(): 【初始化】 这是最复杂的阶段,顺序如下:
    1. invokeAwareMethods(): 调用 BeanNameAware, BeanFactoryAware 等接口。
    2. applyBeanPostProcessorsBeforeInitialization(): 调用所有 BeanPostProcessorpostProcessBeforeInitialization 方法。
    3. invokeInitMethods(): 调用 afterPropertiesSet() (InitializingBean) 或自定义的 init-method
    4. applyBeanPostProcessorsAfterInitialization(): 【AOP 关键点】 调用所有 BeanPostProcessorpostProcessAfterInitialization 方法。AOP 就是在这里通过 AnnotationAwareAspectJAutoProxyCreator 将原始对象包装成代理对象的。

循环依赖的解决

Spring 用来解决单例 Bean Setter 注入循环依赖的“三级缓存”机制

DefaultSingletonBeanRegistry这个来解决

doGetBean() -> getSingleton(String beanName, ObjectFactory<?> singletonFactory)开始

singletonObjects (一级缓存): Map<String, Object>,存放完全初始化好的 Bean,是最终的成品。

earlySingletonObjects (二级缓存): Map<String, Object>,存放提前暴露的、未完成初始化的 Bean。这个 Bean 可能是原始对象,也可能是已经过 AOP 代理的对象。

singletonFactories (三级缓存): Map<String, ObjectFactory<?>>,存放一个能产生 Bean 的工厂 ObjectFactory(通常是一个 Lambda 表达式)。工厂的目的是推迟代理对象的创建。

例子:

A 正在创建,实例化后,将一个 () -> getEarlyBeanReference(beanName, mbd, bean)ObjectFactory 放入三级缓存 singletonFactories

A 在属性填充时发现需要 B,于是去创建 B。

B 在创建过程中发现需要 A,于是去 getBean(A)

getBean(A) 时,先查一级缓存(无),再查二级缓存(无),最后查到三级缓存中有 A 的工厂。

执行 A 的 ObjectFactory,调用 getEarlyBeanReference(),如果 A 需要被代理,就在此时创建代理对象,否则返回原始对象。然后将结果放入二级缓存 earlySingletonObjects,并移除三级缓存中的工厂。B 获得了 A 的(代理)对象,完成创建。

B 创建完毕,A 获得了 B 的对象,也完成创建,最终放入一级缓存

  • 空间换时间延迟计算。通过增加缓存来解决对象创建过程中的时序问题。三级缓存的核心思想是,只有在真正发生循环依赖时,才通过 ObjectFactory 去提前创建(可能存在的)代理对象。

AOP

动态代理

AOP 是如何通过“运行时织入”的方式,在不侵入业务代码的前提下,为其附加新功能的。掌握两种动态代理技术的底层原理及其在 Spring 中的应用。

动态代理模式:

JDK: java.lang.reflect.Proxy, java.lang.reflect.InvocationHandler

CGLIB: net.sf.cglib.proxy.Enhancer, net.sf.cglib.proxy.MethodInterceptor

Spring 封装: AopProxyFactory, JdkDynamicAopProxy, ObjenesisCglibAopProxy

跟踪 DefaultAopProxyFactory.createAopProxy() 方法:

DefaultAopProxyFactory.createAopProxy()这个方法是Spring AOP创建代理对象的决策中心。它的核心职责就是根据目标对象的特征,决定到底使用哪种动态代理技术来创建代理

如果目标对象实现了一个或多个接口,Spring默认会选择使用 JDK动态代理。它会在运行时动态创建一个新的代理类,这个代理类实现了目标对象所实现的所有接口,并将方法调用转发给一个InvocationHandler进行处理。

如果目标对象没有实现任何接口,那么JDK动态代理就无法工作了。此时,Spring会选择使用 CGLIB代理,CGLIB通过在运行时动态创建一个目标类的子类来作为代理。因为它使用的是继承,所以不要求目标类实现接口。

还有一个关键配置会影响这个决策,那就是proxyTargetClass属性。

  • 如果proxy-target-class被设置为true(在Spring Boot中这是默认设置),那么createAopProxy()方法会跳过接口检查,直接选择使用CGLIB代理。这样做的好处是统一了代理行为,避免了因目标对象是否有接口而导致代理方式不同的问题,并且可以直接代理类本身的方法,而不仅仅是接口方法。

代理链路

Spring AOP 从解析切面 (@Aspect) 到创建代理,再到执行通知 (Advice)

重要的类:

AnnotationAwareAspectJAutoProxyCreator: 最核心的 BeanPostProcessor,驱动整个 AOP 流程。

Advisor: Spring AOP 的内部最小单元,包含一个 Pointcut 和一个 Advice

Advised: 代理对象的配置信息持有者。

ReflectiveMethodInvocation: 方法调用链的实现,负责依次执行拦截器。

步骤:

代理创建: 如前所述,发生在 AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInitialization 方法中。它会调用 wrapIfNecessary()

寻找匹配的 Advisor: 在 wrapIfNecessary() 内部,会调用 findCandidateAdvisors() 找到所有切面,然后通过 findAdvisorsThatCanApply() 根据切入点表达式(Pointcut)筛选出适用于当前 Bean 的所有 Advisor

创建代理: 如果找到 Advisor,则调用 createProxy() 创建代理对象。

代理执行: 当调用代理对象的方法时,会进入 JdkDynamicAopProxy.invoke()CglibAopProxy.DynamicAdvisedInterceptor.intercept()

构建拦截器链: 代理逻辑会从 Advised 配置中获取所有适用的 Advisor,并将它们转换成一个拦截器链(List<Object> chain)。

链式调用: 创建一个 ReflectiveMethodInvocation 实例,并调用其 proceed() 方法。proceed() 方法会依次调用链中的每一个拦截器(即 Advice),最后调用目标方法。

事务

Spring 如何巧妙地利用 AOP 将命令式的、与业务逻辑高度耦合的事务代码(try-catch-finally, commit, rollback)“剥离”出去,转化为声明式的、以注解驱动的优雅实现。核心在于理解“围绕方法调用的事务边界控制

原理

Spring 事务管理的核心是 AOP 代理,并且其实现依赖于一个与具体数据访问技术解耦的抽象层。

核心类:

PlatformTransactionManager: 事务管理器的核心策略接口。不同的数据访问技术有不同的实现

TransactionDefinition: 定义事务的属性,如隔离级别 (Isolation)传播行为 (Propagation)、超时、是否只读。

TransactionInterceptor: AOP 通知 (Advice) 的具体实现,是驱动事务管理的核心逻辑所在。

TransactionSynchronizationManager: 事务同步管理器。它使用 ThreadLocal 来保存和管理当前线程的事务状态(如连接、TransactionStatus),是确保事务在单线程内正确运行和线程安全的关键。

步骤:

入口:当一个被 @Transactional 注解的方法被调用时,AOP 代理会拦截这个调用。

拦截器介入:调用被转发到 TransactionInterceptorinvoke() 方法。

核心处理invoke() 方法直接委托给父类 TransactionAspectSupportinvokeWithinTransaction() 方法。这是整个事务模块的心脏

invokeWithinTransaction() 内部流程

a. 获取事务属性:通过 TransactionAttributeSource 解析方法上的 @Transactional 注解,获取 TransactionDefinition

b. 获取事务管理器:确定要使用的 PlatformTransactionManager

c. 开启事务:调用 transactionManager.getTransaction(txAttr)。这是传播行为生效的地方。管理器会查询 TransactionSynchronizationManager,检查当前线程是否已存在事务: 若无事务且传播行为为 REQUIRED / REQUIRES_NEW / NESTED,则开启一个新事务,并将数据库连接和事务状态绑定到当前线程。 若有事务且传播行为为 REQUIRED / SUPPORTS,则加入当前事务。 * 若有事务且传播行为为 REQUIRES_NEW,则挂起当前事务,开启一个全新的事务。

d. 执行业务逻辑:将事务状态 TransactionStatus 准备好后,在一个 try-catch 块中,调用 invocation.proceed(),执行原始的业务方法。

e. 提交事务:如果业务方法正常执行完毕,则调用 commitTransactionAfterReturning(),内部最终会调用 transactionManager.commit(status)

f. 回滚事务:如果业务方法抛出异常,catch 块会捕获它。completeTransactionAfterThrowing() 会被调用,它会检查抛出的异常是否满足回滚规则(默认是 RuntimeExceptionError),如果满足,则调用 transactionManager.rollback(status)

根据我们的spring事务的底层原理我们可以知道,我们事务失效的场景有哪些?

  1. 跳过了AOP代理

    1. this直接调用,跳过了AOP代理
    2. 权限错误,Spring AOP默认使用CGLIB创建代理,它通过继承目标类并重写public方法来实现。
    3. 方法被 final 修饰,一个被final修饰的方法无法被子类重写,因此AOP无法对其进行代理。
    4. 方法被 static 修饰static方法属于类,而不属于任何实例。Spring的AOP是基于实例的代理,无法代理静态方法。
  2. 异常

    1. 异常被try-catch块捕获且未抛出,AOP的回滚是依赖捕获到了从事务方法中抛出的异常
    2. 抛出的异常类型不被默认回滚规则覆盖,异常的类型错误,在遇到 RuntimeException(非受检异常)或 Error 时才会触发回滚
  3. 事务传播

    1. 事务传播行为(Propagation)配置不当,比如NOT_SUPPORTED,NEVER
  4. 外部环境

    1. 数据库引擎不支持事务,比如MyISAM引擎的Mysql
    2. Spring相关配置问题@SpringBootApplication所在的启动类无法扫描到你的Service包。 2. 忘记在启动类上添加@EnableTransactionManagement注解

MVC

流程:

入口:所有 HTTP 请求进入 DispatcherServletservice() 方法,最终由 doDispatch() 方法处理。doDispatch() 是 Spring MVC 的“主循环”

doDispatch()

内部流程:

a. getHandler(): 遍历所有注册的 HandlerMapping,调用它们的 getHandler() 方法,直到找到一个匹配当前请求的 HandlerExecutionChain。这个 Chain 对象中包含了真正的处理器(HandlerMethod)和应用于它的所有拦截器。

b. getHandlerAdapter(): 遍历所有注册的 HandlerAdapter,找到一个支持上一步得到的 Handler 的适配器。

c. applyPreHandle(): 按顺序执行 HandlerExecutionChain 中所有拦截器的 preHandle() 方法。如果任何一个返回 false,则请求处理中断。

d. handlerAdapter.handle(): 核心调用RequestMappingHandlerAdapterhandle() 方法会委托给 invokeHandlerMethod()。此方法内部:

​ i. 通过 HandlerMethodArgumentResolver 链,解析并准备 Controller 方法所需的所有参数。

​ ii. 通过反射调用真正的 Controller 方法。

 iii. 通过 `HandlerMethodReturnValueHandler` 链,处理 Controller 方法的返回值,并将其封装到 `ModelAndView` 对象中。 

e. applyPostHandle(): 倒序执行所有拦截器的 postHandle() 方法。

f. processDispatchResult(): 处理 ModelAndView。调用 render() 方法,render() 方法会使用 ViewResolver 找到对应的 View 对象,然后调用 view.render() 将模型数据渲染到响应中。

g. triggerAfterCompletion(): 在 finally 块中,无论成功与否,都会倒序执行拦截器的 afterCompletion() 方法,用于资源清理。

当然根据这个我们也可以将MVC的设计应用到一些重复性的工作之中,prehandel进行前置处理,finally进行后置处理

Boot

Spring Boot “约定大于配置” 的神秘面纱。理解其本质并非“魔法”,而是一套基于 Classpath 内容环境配置的、条件化的可插拔的 Bean 注册机制。

掌握 Spring Boot 是如何通过 @EnableAutoConfiguration 扫描、加载、并根据条件(@Conditional)过滤配置类,最终完成 Bean 自动注册的全过程。

流程:

起点SpringApplication.run() 启动应用,创建 ApplicationContext

触发:在容器 refresh 过程中,Spring 会解析主配置类上的 @SpringBootApplication 注解,进而处理其元注解 @EnableAutoConfiguration

导入选择器@EnableAutoConfiguration 通过 @Import(AutoConfigurationImportSelector.class) 引入了 AutoConfigurationImportSelector

收集候选配置:Spring 会调用 AutoConfigurationImportSelectorselectImports() 方法。该方法会:

a. 调用 getCandidateConfigurations(),它使用 SpringFactoriesLoader (或新的 AutoConfiguration 机制) 去扫描所有 classpath 下的 JAR 包,读取 spring.factories.imports 文件中 org.springframework.boot.autoconfigure.EnableAutoConfiguration key 下的自动配置类全名列表。

过滤与评估:得到这个庞大的候选列表后,并不会全部加载,而是进行严格的过滤:

a. 首先,移除用户通过 exclude 属性明确排除的配置类。

b. 然后,最重要的步骤:遍历每一个候选配置类,使用 ConditionEvaluator 检查该类上的所有 @Conditional... 注解。

c. 例如,DataSourceAutoConfiguration 上有 @ConditionalOnClass(DataSource.class),评估器会检查 DataSource.class 是否存在于当前 Classpath。RabbitAutoConfiguration 上的 @ConditionalOnClass(RabbitTemplate.class) 会检查 RabbitMQ 的客户端库是否存在。

d. 只有所有条件都满足的配置类,才会被认为是“激活”的。

最终加载selectImports() 方法最终返回一个“激活”的配置类名称数组。Spring 会像处理普通的 @Configuration 类一样,将它们加载到 IoC 容器中,执行其中的 @Bean 方法,从而完成 Bean 的自动配置。

理解

SPI (Service Provider Interface)spring.factories / .imports 文件机制是一种 SPI 的实现,它允许第三方库(starters)向 Spring Boot “注册”自己的自动配置能力,实现了完美的解耦和可插拔性。

约定大于配置 (Convention over Configuration):Spring Boot 替你做了最佳实践的预设。例如,只要 spring-boot-starter-web 在 classpath 中,它就“约定”你可能需要一个内嵌的 Tomcat 和一个配置好的 DispatcherServlet

条件化配置 (Conditional Configuration)@Conditional 注解是整个自动配置体系的基石,它让配置变得智能和按需加载,避免了不必要的资源消耗和配置冲突。