📌 本文定位:把 Spring IOC(控制反转)这个最核心的概念讲透。不只会说"IOC 把控制权交给容器",要能画出 Bean 生命周期流程图、写出手动模拟 IOC 的 Demo、答上面试官的灵魂追问。

🎯 适合人群

  • 用了 Spring 很久但没搞懂"容器到底干了啥"的同学
  • 面试被问 Bean 生命周期时支支吾吾的……就是你
  • 想从"会用"进阶到"懂原理"的 Java 学习者

📑 目录

文章目录


1. 先搞懂三个词:IOC / DI / DL

面试常问:“说说你对 IOC 的理解。” 大部分人张口就背——“控制反转,把对象的创建权交给 Spring 容器。”

问题是,"控制"指什么?"反转"对比的是什么?

1.1 传统方式 vs IOC 方式

传统方式(主动创建):

public class UserService {
    // 自己 new —— 我来控制对象的创建
    private UserDao userDao = new UserDaoImpl();
    private UserDao oracleDao = new OracleUserDaoImpl();

    public void doSomething() {
        userDao.save();
    }
}

问题:UserServiceUserDaoImpl 强耦合。想换 Oracle 实现?改代码。

IOC 方式(被动注入):

public class UserService {
    // 我不 new 了,你(容器)给我
    private UserDao userDao;

    // 通过构造器/Setter 传入
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public void doSomething() {
        userDao.save();
    }
}

然后告诉容器:

<bean id="userDao" class="com.example.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.example.service.UserService">
    <constructor-arg ref="userDao"/>
</bean>

或者用注解:

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
}

1.2 一句话说清楚

概念 全称 一句话
IOC Inversion of Control 控制反转——对象的创建权从"程序员手动 new"反转给"容器管理"
DI Dependency Injection 依赖注入——容器把对象需要的依赖(另一个对象)自动传给它
DL Dependency Lookup 依赖查找——主动从容器里 getBean() 获取(用得少,不推荐)

IOC 是设计思想,DI 是实现方式。 Spring 通过 DI 实现了 IOC。

1.3 传统 vs IOC 对比

┌────────────────────┐        ┌────────────────────┐
│   传统方式          │        │   Spring IOC       │
│                    │        │                    │
│  你的代码          │        │  你的代码           │
│    ├─ new A()      │        │    ├─ @Autowired   │
│    ├─ new B(A)     │        │    └─ 等容器注入    │
│    └─ new C(B)     │        │                    │
│                    │        │  ┌──────────┐      │
│  你得自己管         │        │  │ IOC容器   │      │
│  对象的创建         │        │  │ 创建→管理 │      │
│  和生命周期         │        │  │ 注入→销毁 │      │
│                    │        │  └──────────┘      │
│  控制权:你        │        │  控制权:容器       │
└────────────────────┘        └────────────────────┘

1.4 为什么要有 IOC?

  • 解耦:不再 new() 死一个实现类,换实现不换代码
  • 方便测试:注入 Mock 对象
  • 管理生命周期:单例、原型、作用域由容器统一管
  • AOP 的基础:没有容器代理,AOP 切不进去

2. IOC 容器长什么样?

Spring 的 IOC 容器本质就是一个 大 Map

// 极度简化的理解
public class SimpleIocContainer {
    // key: beanName, value: bean 实例
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    public Object getBean(String name) {
        return singletonObjects.get(name);
    }

    public void registerBean(String name, Object bean) {
        singletonObjects.put(name, bean);
    }
}

当然真实源码复杂得多,但核心思想就是:容器启动时扫描配置 → 创建 Bean → 放进 Map → 谁用谁取

2.1 BeanFactory——老祖宗

public interface BeanFactory {
    Object getBean(String name);
    <T> T getBean(Class<T> requiredType);
    boolean containsBean(String name);
    boolean isSingleton(String name);
    // ...
}

BeanFactory 是 IOC 容器的顶层接口,延迟加载——你调 getBean() 时才创建对象。

2.2 ApplicationContext——高级容器

public interface ApplicationContext extends BeanFactory {
    // 继承了 BeanFactory,还多了:
    // 国际化(MessageSource)
    // 事件发布(ApplicationEventPublisher)
    // 资源访问(ResourceLoader)
    // 环境抽象(EnvironmentCapable)
}

ApplicationContext启动时预加载所有单例 Bean(饿汉模式)。

特性 BeanFactory ApplicationContext
加载策略 延迟加载(用到才创建) 预加载(启动时创建所有单例)
国际化
事件机制
自动注册 BeanPostProcessor ❌(需手动)
常用实现类 XmlBeanFactory(已废弃) ClassPathXmlApplicationContextAnnotationConfigApplicationContext

结论:日常开发直接用 ApplicationContext,几乎不用 BeanFactory。

2.3 主流实现类

// 1. 基于 XML(老项目)
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

// 2. 基于注解配置(现代项目)
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

// 3. 基于 Spring Boot(默认)
// SpringApplication.run() 内部创建的就是 AnnotationConfigApplicationContext

3. 三种依赖注入方式详解

面试必问:Spring 有哪几种注入方式?推荐哪种?为什么?

3.1 构造器注入(✅ 推荐)

@Service
public class OrderService {

    private final UserService userService;
    private final ProductService productService;

    // Spring 自动匹配参数,按类型注入
    public OrderService(UserService userService, ProductService productService) {
        this.userService = userService;
        this.productService = productService;
    }
}

优点:

  • 不可变性:final 关键字,注入后不可修改
  • 依赖完整性:构造时依赖必须全部就绪,不会出现 NPE
  • 方便测试:直接 new OrderService(mockUserService, mockProductService),不需要反射

3.2 Setter 注入

@Service
public class OrderService {

    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

特点:

  • 可选依赖可以用 Setter
  • 可以后续修改(不推荐)
  • 对象创建后可能依赖还未注入

3.3 字段注入(❌ 不推荐)

@Service
public class OrderService {

    @Autowired       // 直接在字段上
    private UserService userService;

    @Autowired
    private ProductService productService;
}

缺点:

  • 无法用 final,对象可变
  • 无法直接 new 测试,必须依赖 Spring 容器或反射
  • 隐藏了依赖关系,类看起来很"干净",但外部看不到它依赖什么

3.4 对比总结

维度 构造器注入 Setter 注入 字段注入
不可变性 ✅ 支持 final
依赖完整性 ✅ 必须完整 ⚠️ 可能遗漏 ⚠️ 可能遗漏
单元测试 ✅ 直接 new ✅ 直接 new ❌ 需反射/Spring
循环依赖解决 ❌ 无法解决 ✅ 可解决 ✅ 可解决
官方推荐 ✅ 强烈推荐 可选依赖可用 ❌ 不推荐

💡 一句话:能用构造器就不要用字段注入。 Spring 官方在文档里明确推荐构造器注入。


4. Bean 生命周期——面试核心考点

这是面试最常考、也最能拉开差距的题。别只背那几个名字,要理解顺序和为什么。

4.1 完整生命周期流程图

┌────────────────────────────────────────────────────────────────────┐
│                   Bean 完整生命周期(13 步)                        │
│                                                                    │
│  1. 类加载 → 通过反射获取 Bean 的 Class 元信息                       │
│         │                                                          │
│         ▼                                                          │
│  2. 实例化 → 反射调用构造器创建原始对象 (new)                        │
│         │                                                          │
│         ▼                                                          │
│  3. 属性赋值 → 填充 @Autowired、@Value、XML <property> 等           │
│         │                                                          │
│         ▼                                                          │
│  4. Aware 接口回调                                                 │
│     ├─ BeanNameAware.setBeanName()                                 │
│     ├─ BeanClassLoaderAware.setBeanClassLoader()                   │
│     └─ BeanFactoryAware.setBeanFactory()                           │
│         │                                                          │
│         ▼                                                          │
│  5. BeanPostProcessor#postProcessBeforeInitialization              │
│     (初始化前处理,这里可以做代理、包装等)                             │
│         │                                                          │
│         ▼                                                          │
│  6. InitializingBean#afterPropertiesSet()                         │
│     (或 @PostConstruct / init-method)                              │
│         │                                                          │
│         ▼                                                          │
│  7. BeanPostProcessor#postProcessAfterInitialization               │
│     (初始化后处理,⭐ AOP 动态代理就在这里生成!)                     │
│         │                                                          │
│         ▼                                                          │
│  8. Bean 就绪 → 可以被注入到其他 Bean 中使用                        │
│         │                                                          │
│         ▼                                                          │
│  9. DisposableBean#destroy()                                       │
│     (或 @PreDestroy / destroy-method)                              │
│         │                                                          │
│         ▼                                                          │
│  10. 销毁                                                         │
└────────────────────────────────────────────────────────────────────┘

4.2 步骤详解(按顺序)

① 实例化

调用构造器创建原始对象,此时属性全是默认值。

// 底层通过反射
Constructor<?> constructor = beanClass.getDeclaredConstructor();
Object bean = constructor.newInstance();
② 属性赋值

把配置的属性填充进去。

// 简化:遍历 @Autowired 字段,反射 set
Field field = beanClass.getDeclaredField("userService");
field.setAccessible(true);
field.set(bean, userServiceBean);
③ Aware 接口回调

如果 Bean 实现了 Aware 子接口,就把容器相关信息告诉它。

public class MyBean implements BeanFactoryAware {
    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }
}
④ BeanPostProcessor#postProcessBeforeInitialization

初始化之前的"预处理"机会。可以对 Bean 做包装、修改。

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if (bean instanceof UserService) {
            System.out.println("UserService 初始化前...");
        }
        return bean;  // 可以返回包装后的对象
    }
}
⑤ 初始化(InitializingBean / @PostConstruct / init-method)
@Component
public class MyBean implements InitializingBean {

    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct 执行");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("InitializingBean.afterPropertiesSet() 执行");
    }
}

执行顺序: @PostConstructInitializingBean.afterPropertiesSet()init-method

⑥ BeanPostProcessor#postProcessAfterInitialization

⭐ 这是 AOP 动态代理生成的地方!

@Component
public class AopBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        // 如果有 @Transactional / @Aspect 注解,生成 JDK 动态代理或 CGLIB 代理
        if (bean.getClass().isAnnotationPresent(Transactional.class)) {
            return Proxy.newProxyInstance(/* ... */);  // 返回代理对象
        }
        return bean;
    }
}
⑦ Bean 就绪

Bean 正式放入 singletonObjects 这个 Map 中,供其他地方注入使用。

⑧ 销毁

容器关闭时调用。

@Component
public class MyBean implements DisposableBean {
    @PreDestroy
    public void preDestroy() {
        System.out.println("@PreDestroy 执行");
    }

    @Override
    public void destroy() {
        System.out.println("DisposableBean.destroy() 执行");
    }
}

4.3 关键源码入口

// AbstractAutowireCapableBeanFactory.java —— 核心方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 1. 实例化
    BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);

    // 2. 属性赋值
    populateBean(beanName, mbd, instanceWrapper);

    // 3. 初始化(包含 Aware + BeanPostProcessor + init)
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    // 3.1 调用 Aware 接口
    invokeAwareMethods(beanName, bean);

    // 3.2 BeanPostProcessor before
    Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

    // 3.3 执行初始化
    invokeInitMethods(beanName, wrappedBean, mbd);

    // 3.4 BeanPostProcessor after(AOP 代理在这里)
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

    return wrappedBean;
}

5. 循环依赖——三级缓存怎么解决?

5.1 什么是循环依赖?

@Service
public class AService {
    @Autowired
    private BService bService;  // A 依赖 B
}

@Service
public class BService {
    @Autowired
    private AService aService;  // B 依赖 A
}

你 new A,A 要 B,new B,B 要 A——死循环

5.2 Spring 的三级缓存

public class DefaultSingletonBeanRegistry {

    /** 一级缓存:singletonObjects —— 完全创建好的 Bean */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** 二级缓存:earlySingletonObjects —— 早期暴露的 Bean(刚实例化,未完成属性赋值) */
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

    /** 三级缓存:singletonFactories —— 存放 ObjectFactory,用来生成早期暴露的 Bean */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
}

5.3 解决流程(以 A → B → A 为例)

时间线 ↓

1. getBean("a")
   ├─ 实例化 A(new AService())→ 原始对象
   ├─ 把 A 放入三级缓存:singletonFactories.put("a", () -> getEarlyBeanReference("a"))
   ├─ 开始属性赋值 → 发现需要 B
   │
   ├─ 2. getBean("b")
   │    ├─ 实例化 B(new BService())→ 原始对象
   │    ├─ 把 B 放入三级缓存
   │    ├─ 开始属性赋值 → 发现需要 A
   │    │
   │    ├─ 3. getBean("a") 再次
   │    │    ├─ 一级缓存 singletonObjects 没有 A(还没放)
   │    │    ├─ 二级缓存 earlySingletonObjects 没有 A(还没放)
   │    │    ├─ 三级缓存 singletonFactories 有 A!
   │    │    ├─ 拿到 A 的 ObjectFactory,执行 getObject() 得到早期 A
   │    │    ├─ 把早期 A 提升到二级缓存 earlySingletonObjects
   │    │    └─ 返回早期 A 给 B
   │    │
   │    └─ B 拿到 A 的引用,完成属性赋值
   │        └─ B 走完完整生命周期 → 放入一级缓存 singletonObjects
   │
   └─ A 拿到 B(已完成),继续完成属性赋值
       └─ A 走完完整生命周期 → 放入一级缓存 singletonObjects
       └─ 清理 A 在二级、三级缓存的记录

5.4 关键结论

问题 答案
三级缓存解决了什么? 未完成初始化的 Bean 提前暴露给其他 Bean 引用
为什么要三级?二级不行? 三级缓存存的是 ObjectFactory,可以在提前暴露时执行 AOP 增强。如果直接用二级存原始对象,AOP 代理就丢了
构造器注入能解决循环依赖吗? 不能! 构造器注入在实例化阶段就要求参数就绪,那时三级缓存还没放东西
原型作用域能解决吗? 不能! 原型 Bean 不缓存,每次都新创建

💡 面试高频题:你遇到过循环依赖吗?怎么解决的?

回答策略:先解释什么是循环依赖 → Spring 三级缓存机制 → 然后说实际开发中应该通过重构代码避免循环依赖,而不是依赖三级缓存。可以提取公共依赖、改用构造器注入(构造器注入报错能提前发现问题)。


6. 手写一个微型 IOC 容器

理解了原理,写个超简版感受一下:

6.1 定义注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {
    String value() default "";
}

@Target({ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAutowired {
}

6.2 手写 IOC 容器

public class MyApplicationContext {

    // 一级缓存:存放所有 Bean 实例
    private final Map<String, Object> beanMap = new ConcurrentHashMap<>();

    public MyApplicationContext(String basePackage) {
        // 1. 扫描包下所有带 @MyComponent 的类
        Set<Class<?>> classes = scanPackage(basePackage);

        // 2. 实例化所有 Bean(放入 map)
        for (Class<?> clazz : classes) {
            String beanName = getBeanName(clazz);
            beanMap.put(beanName, clazz.getDeclaredConstructor().newInstance());
        }

        // 3. 执行依赖注入
        for (Class<?> clazz : classes) {
            String beanName = getBeanName(clazz);
            Object bean = beanMap.get(beanName);
            injectDependencies(bean, clazz);
        }
    }

    private Set<Class<?>> scanPackage(String basePackage) {
        // 实际项目中用 ClassPathScanningCandidateComponentProvider
        // 这里为简化,手动注册
        Set<Class<?>> classes = new HashSet<>();
        // ... 扫描逻辑(略,详见下文 Demo)
        return classes;
    }

    private void injectDependencies(Object bean, Class<?> clazz) throws Exception {
        // 遍历所有字段,找 @MyAutowired
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(MyAutowired.class)) {
                Object dependency = beanMap.get(field.getName());
                field.setAccessible(true);
                field.set(bean, dependency);
            }
        }
    }

    private String getBeanName(Class<?> clazz) {
        MyComponent component = clazz.getAnnotation(MyComponent.class);
        String value = component.value();
        if (value.isEmpty()) {
            // 默认:首字母小写的类名
            String simpleName = clazz.getSimpleName();
            return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
        }
        return value;
    }

    @SuppressWarnings("unchecked")
    public <T> T getBean(String name) {
        return (T) beanMap.get(name);
    }
}

6.3 测试

@MyComponent
public class UserDao {
    public void save() {
        System.out.println("保存用户...");
    }
}

@MyComponent
public class UserService {

    @MyAutowired
    private UserDao userDao;

    public void doSomething() {
        userDao.save();
    }
}

// 运行
public class Main {
    public static void main(String[] args) {
        MyApplicationContext ctx = new MyApplicationContext("com.example");
        UserService userService = ctx.getBean("userService");
        userService.doSomething();  // 输出:保存用户...
    }
}

虽然只有几十行,但已经包含了 IOC 容器的核心逻辑:扫描 → 实例化 → 注入 → 使用


7. Bean 的作用域

@Component
@Scope("singleton")     // 默认值,可以省略
public class UserService { }

@Component
@Scope("prototype")
public class OrderService { }
作用域 说明 适用场景
singleton(默认) 整个容器只有一个实例 无状态 Bean(Service、DAO)
prototype 每次 getBean() 都创建新实例 有状态 Bean
request 每个 HTTP 请求一个实例 Web 应用
session 每个 HTTP Session 一个实例 Web 应用
application 每个 ServletContext 一个实例 Web 应用

8. @Component vs @Bean

面试也爱问这个区别:

维度 @Component @Bean
使用位置 类级别 方法级别(在 @Configuration 类中)
谁写的类 你自己的类 第三方类(你改不了源码)
创建方式 框架自动实例化 你自己写 new 逻辑
典型场景 UserServiceUserDao RestTemplateDataSourceRedisTemplate
// @Component 用在自己的类上
@Component
public class UserService { }

// @Bean 用在第三方类上
@Configuration
public class AppConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

9. 面试高频问答

Q1:IOC 是什么?有什么好处?

:IOC(控制反转)是一种设计思想,将对象的创建、组装和管理控制权从程序代码转移到 IOC 容器。好处:

  1. 解耦:组件之间通过接口交互,不依赖具体实现
  2. 可测试性:可以注入 Mock 对象进行单元测试
  3. 统一管理:对象的生命周期(创建 → 初始化 → 销毁)由容器统一管理
  4. AOP 的基础:没有容器代理,AOP 切不进去

Q2:依赖注入有哪几种方式?Spring 推荐哪种?

:三种方式:

  1. 构造器注入(✅ 推荐):依赖不可变、注入完整、方便测试。Spring 官方推荐
  2. Setter 注入:适合可选依赖,但对象可能不完整
  3. 字段注入(❌ 不推荐):代码最简洁,但无法用 final,无法直接 new 测试,隐藏了依赖关系

Q3:Bean 的生命周期能不能说一遍?

:分 8 个阶段(从简单到详细):

实例化:反射调用构造器创建原始对象
属性赋值:填充 @Autowired、@Value
Aware 回调:调用 BeanNameAware、BeanFactoryAware 等
BeanPostProcessor#before:初始化前处理
初始化:@PostConstruct → InitializingBean → init-method
BeanPostProcessor#after:⭐ AOP 代理在这里生成
就绪使用:放入容器,供注入
销毁:@PreDestroy → DisposableBean → destroy-method

关键源码入口在 AbstractAutowireCapableBeanFactory.doCreateBean()initializeBean() 方法。

Q4:三级缓存解决循环依赖的原理?

:Spring 通过三级缓存(singletonObjects / earlySingletonObjects / singletonFactories)解决单例 setter 注入的循环依赖。

核心思路:先实例化,暴露早期引用,再填充属性

A 实例化后放入三级缓存(ObjectFactory),填充属性时发现需要 B → 去创建 B → B 填充属性时需要 A → 从三级缓存拿到 A 的早期引用 → B 完成创建 → A 拿到完整的 B → A 完成创建。

注意:构造器注入和 prototype 作用域无法解决循环依赖

Q5:@Component@Bean 的区别?

  • @Component 用于类级别,框架自动扫描实例化,适用于自己写的类
  • @Bean 用于 @Configuration 类中的方法,需要手动 new,适用于第三方类(如 DataSource、RestTemplate)

简单说:自己的类用 @Component,第三方的类用 @Bean。

Q6:BeanFactory 和 ApplicationContext 有什么区别?

  1. 加载策略:BeanFactory 延迟加载,ApplicationContext 预加载所有单例
  2. 功能扩展:ApplicationContext 继承了 BeanFactory,还多了国际化、事件发布、资源访问、Environment 抽象
  3. 自动注册:ApplicationContext 自动注册 BeanPostProcessor 和 BeanFactoryPostProcessor,BeanFactory 需要手动

日常开发直接用 ApplicationContext。

Q7:singleton Bean 是线程安全的吗?

不是天生的。单例意味着多个线程共享同一个 Bean 实例,如果 Bean 中有可变状态(实例变量),就可能出现线程安全问题。

解决方式:

  1. 无状态设计(推荐):Service 层方法只操作局部变量 + 参数,不保存实例变量
  2. ThreadLocal:如 SimpleDateFormat 的线程安全问题
  3. 加锁synchronizedLock(不推荐,影响性能)

Q8:Spring 是怎么管理 Bean 的单例的?

:实际上就是 ConcurrentHashMap

DefaultSingletonBeanRegistry 中,维护了一个 Map<String, Object> singletonObjects。Bean 创建完成后就 put 进去,getBean 时先从 map 取,取不到才创建。线程安全通过 synchronized 块 + ConcurrentHashMap 保证。


10. 总结 + 推荐阅读

核心一句话

Spring IOC = 容器接管对象的全生命周期(创建 → 注入 → 初始化 → 销毁),你只需要关注业务逻辑。

知识点脑图

Spring IOC 原理
├── IOC 概念
│   ├── 控制反转:创建权交给容器
│   ├── 依赖注入:容器自动注入依赖
│   └── 好处:解耦、可测试、统一管理
├── IOC 容器
│   ├── BeanFactory(延迟加载)
│   └── ApplicationContext(预加载)
├── 依赖注入方式
│   ├── 构造器注入 ✅
│   ├── Setter 注入
│   └── 字段注入 ❌
├── Bean 生命周期(8 步)
│   ├── 实例化 → 属性赋值 → Aware → Before → init → After → 就绪 → 销毁
│   └── 关键:BeanPostProcessor#after → AOP 代理
├── 循环依赖(三级缓存)
│   ├── 一级:完整 Bean
│   ├── 二级:早期 Bean
│   └── 三级:ObjectFactory
└── 作用域
    ├── singleton(默认)
    ├── prototype
    └── request / session / application

推荐源码阅读路径

去 IDE 里 Debug 跟踪一遍,比看 10 篇文章都管用:

// 入口:随便写一个 @Component,断点打在以下方法
AbstractApplicationContext.refresh()                          // 容器启动finishBeanFactoryInitialization()                       // 初始化所有单例 BeanDefaultListableBeanFactory.preInstantiateSingletons()AbstractBeanFactory.getBean()AbstractAutowireCapableBeanFactory.doCreateBean()  // ⭐ 核心createBeanInstance()                    // ① 实例化populateBean()                          // ② 属性赋值initializeBean()                        // ③ 初始化(含 BeanPostProcessor)
推荐阅读的类/方法 关注点
AbstractAutowireCapableBeanFactory.doCreateBean() Bean 创建的完整流程
AbstractAutowireCapableBeanFactory.populateBean() 属性如何注入
AbstractAutowireCapableBeanFactory.initializeBean() Aware → Before → Init → After
DefaultSingletonBeanRegistry.getSingleton() 三级缓存获取逻辑
DefaultSingletonBeanRegistry.addSingletonFactory() 三级缓存注册逻辑

💡 Debug 技巧:写一个最简单的 @Service + @Autowired 项目,在 doCreateBean() 打上断点,按 F7 一步步跟踪,看着 Bean 从无到有、从原始对象到 AOP 代理的完整过程——这种体验是任何文字都无法替代的。


📌 写在最后:IOC 是 Spring 的基石,搞懂它之后 Spring AOP、事务管理、源码阅读都会豁然开朗。建议你把第 6 节的 手写 IOC 容器 自己敲一遍,再配合源码 Debug 跟踪一次,面试问 IOC 你就能碾压 90% 的人。


如果本文对你有帮助,欢迎点赞 👍 收藏 ⭐ 评论 💬,你的支持是我继续写学习笔记的最大动力!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐