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 小白变身编程高手!

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

相关推荐
AnAnCode1 小时前
【时间轮算法】时间轮算法的详细讲解,从基本原理到 Java 中的具体实现
java·开发语言·算法·时间轮算法
JIngJaneIL1 小时前
基于Java二手交易管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot
雨中飘荡的记忆1 小时前
Spring Data JPA详解
java·spring
虚伪的空想家1 小时前
首发:TDengine3.3.6版本使用K8S部署
java·docker·容器·kubernetes·k8s·时序数据库·tdengine
悟空码字1 小时前
SpringBoot实现系统监控:给应用装上“健康手环”
java·后端·监控
葡萄成熟时 !1 小时前
快捷键idea
java
吃喝不愁霸王餐APP开发者1 小时前
外卖霸王餐灰度开关:基于Spring Cloud Config+Bus动态刷新踩坑
java
雨中飘荡的记忆1 小时前
Spring Security详解
java·spring
小许学java1 小时前
网络编程套接字
java·网络·udp·socket·tcp·套接字