Spring IOC 核心源码解析

Spring IOC 核心源码解析

一、核心入口

对于新手来说,不用一上来就啃全量源码,先抓住核心入口类核心流程 :本文以 Spring 6.x 中基于注解的 IOC 容器入口是 AnnotationConfigApplicationContext,创建容器的核心代码:

ini 复制代码
// 最简容器初始化代码
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
NotificationController controller = context.getBean(NotificationController.class);

这一行代码背后,就是 IOC 容器的完整生命周期,我们拆解为 4 个核心步骤:

二、IOC 核心流程源码拆解

步骤 1:容器初始化 - 刷新上下文(核心方法:refresh ())

AnnotationConfigApplicationContext 构造方法最终会调用 AbstractApplicationContextrefresh() 方法,这是 IOC 容器的 "总开关",核心代码简化如下:

scss 复制代码
@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 准备刷新:初始化环境、校验配置
        prepareRefresh();

        // 2. 获取 BeanFactory(核心容器),加载 Bean 定义
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 3. 准备 BeanFactory:设置类加载器、注册内置 Bean 等
        prepareBeanFactory(beanFactory);

        try {
            // 4. 后置处理 BeanFactory(扩展点)
            postProcessBeanFactory(beanFactory);

            // 5. 执行 BeanFactory 后置处理器(扫描并注册 BeanDefinition)
            invokeBeanFactoryPostProcessors(beanFactory);

            // 6. 注册 Bean 后置处理器(处理注解如@Autowired、@PostConstruct)
            registerBeanPostProcessors(beanFactory);

            // 7. 初始化消息源(国际化)
            initMessageSource();

            // 8. 初始化事件广播器
            initApplicationEventMulticaster();

            // 9. 子类扩展:初始化其他 Bean(如 Web 环境的 ThemeSource)
            onRefresh();

            // 10. 注册事件监听器
            registerListeners();

            // 11. 实例化所有非懒加载的单例 Bean(核心!)
            finishBeanFactoryInitialization(beanFactory);

            // 12. 完成刷新:发布事件、初始化 Lifecycle 处理器
            finishRefresh();
        } catch (BeansException ex) {
            // 异常处理:销毁已创建的 Bean
            destroyBeans();
            cancelRefresh(ex);
            throw ex;
        }
    }
}

重点关注:步骤 5(扫描 Bean)和步骤 11(实例化 Bean)是 IOC 的核心中的核心。

步骤 2:扫描 Bean - 生成 BeanDefinition

步骤 5 中,ConfigurationClassPostProcessor 会扫描指定包下的注解类(@Component、@Service、@Controller 等),将每个类封装为 BeanDefinition(Bean 定义元信息,包含类名、作用域、依赖等),并存入 BeanFactorybeanDefinitionMap 中。核心逻辑在 ClassPathBeanDefinitionScannerdoScan() 方法:

ini 复制代码
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        // 扫描包下的类,生成 BeanDefinition
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {
            // 设置作用域(默认单例)
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            // 生成 Bean 名称(默认类名首字母小写)
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            // 处理通用注解(如@Lazy、@Primary)
            AnnotationConfigUtils.processCommonDefinitionAnnotations(candidate);
            // 注册 BeanDefinition 到容器
            if (checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

核心概念BeanDefinition 是 Spring 对 Bean 的 "描述",容器先存描述,再根据描述创建实例,这是 Spring 灵活扩展的关键。

步骤 3:实例化 Bean - createBean ()

步骤 11 中,DefaultListableBeanFactorypreInstantiateSingletons() 方法会遍历所有 BeanDefinition,调用 createBean() 方法创建实例,核心流程:

  1. 创建 Bean 实例 :通过反射调用构造方法(instantiateBean());
  2. 依赖注入 :处理 @Autowired 注解,从容器中获取依赖 Bean 并注入(populateBean());
  3. 初始化 Bean :执行 @PostConstruct 注解方法、初始化方法(initializeBean());
  4. 存入容器 :将创建好的单例 Bean 存入 singletonObjects(单例池)。

核心代码简化:

less 复制代码
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    try {
        // 1. 创建 Bean 实例
        Object beanInstance = doCreateBean(beanName, mbd, args);
        // 2. 依赖注入 + 初始化
        populateBean(beanName, mbd, beanInstance);
        exposedObject = initializeBean(beanName, exposedObject, mbd);
        return exposedObject;
    } catch (BeansException ex) {
        destroyBean(beanName, mbd, beanInstance);
        throw ex;
    }
}

步骤 4:依赖注入 - AutowiredAnnotationBeanPostProcessor

@Autowired 注解的处理核心是 AutowiredAnnotationBeanPostProcessor,它是一个 BeanPostProcessor(Bean 后置处理器),在 populateBean() 阶段执行:

  • 扫描 Bean 的字段 / 方法上的 @Autowired 注解;
  • 根据类型 / 名称从容器中查找依赖的 Bean;
  • 通过反射注入依赖(支持字段注入、构造器注入、setter 注入)。

三、看源码的建议

  1. 先跑通最简案例 :写一个只有 AppConfig + NotificationController 的最简项目,debug 跟踪 AnnotationConfigApplicationContext 的创建流程;
  2. 抓核心不贪全:先搞懂「扫描→BeanDefinition→实例化→注入」4 个核心步骤,再看扩展点(后置处理器、生命周期);

📌 关注我 ,每天5分钟,带你从 Java 小白变身编程高手!

👉 点赞 + 关注,让更多小伙伴一起进步!

相关推荐
NE_STOP1 小时前
MyBatis-mybatis入门与增删改查
java
孟陬4 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
想用offer打牌4 小时前
一站式了解四种限流算法
java·后端·go
华仔啊5 小时前
Java 开发千万别给布尔变量加 is 前缀!很容易背锅
java
也些宝5 小时前
Java单例模式:饿汉、懒汉、DCL三种实现及最佳实践
java
Nyarlathotep01136 小时前
SpringBoot Starter的用法以及原理
java·spring boot
wuwen56 小时前
WebFlux + Lettuce Reactive 中 SkyWalking 链路上下文丢失的修复实践
java
SimonKing6 小时前
GitHub 10万星的OpenCode,正在悄悄改变我们的工作流
java·后端·程序员
Seven977 小时前
虚拟线程深度解析:轻量并发编程的未来趋势
java