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

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

相关推荐
五岳14 小时前
分库分表数据源ShardingSphereDataSource的Connection元数据误用问题分析
java·mysql·爬坑
带刺的坐椅14 小时前
迈向 MCP 集群化:Solon AI (支持 Java8+)在解决 MCP 服务可扩展性上的探索与实践
java·ai·llm·solon·mcp
鼠爷ねずみ15 小时前
SpringCloud前后端整体开发流程-以及技术总结文章实时更新中
java·数据库·后端·spring·spring cloud
代码or搬砖15 小时前
String字符串
android·java·开发语言
AM越.17 小时前
Java设计模式详解--装饰器设计模式(含uml图)
java·设计模式·uml
59803541517 小时前
【java工具类】小数、整数转中文大写
android·java·开发语言
JIngJaneIL17 小时前
基于java + vue个人博客系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
吃喝不愁霸王餐APP开发者17 小时前
Java后端服务在对接全国性霸王餐API时的多数据中心部署与就近调用策略
java·开发语言
从心归零17 小时前
springboot-jpa的批量更新方法
java·spring boot·spring