Spring IOC

Spring IOC

在 Java 后端开发中,Spring 框架无疑是最核心的技术之一。而在 Spring 的核心理念中,IOC(Inversion of Control,控制反转) 是基础中的基础。

一、什么是 IOC(控制反转)?

IOC 即“控制反转”,指将对象的创建与依赖关系管理交给容器(Spring)来完成,而不是在代码中显式创建依赖。

换句话说,传统开发中我们自己 new 依赖,而 IOC 容器通过配置或注解自动将依赖注入给我们。

对比示例:

传统写法:

public class UserService {
    private UserDao userDao = new UserDao();
}

IOC 写法:

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

由此可见,对象的依赖由 Spring 容器控制,程序员只需声明依赖。

二、IOC 容器与 Bean 生命周期

Spring 提供两大 IOC 容器:

  • BeanFactory: 基础容器,懒加载
  • ApplicationContext: 高级容器,立即加载,支持国际化、事件机制等(开发中推荐使用)

Bean 生命周期流程:

  1. 实例化 Bean
  2. 属性注入
  3. 调用 BeanNameAware、BeanFactoryAware 等 Aware 接口
  4. 调用 BeanPostProcessor 的 postProcessBeforeInitialization
  5. 初始化方法(如 @PostConstruct
  6. 调用 BeanPostProcessor 的 postProcessAfterInitialization
  7. Bean 就绪使用
  8. 容器关闭时调用 @PreDestroyDisposableBean.destroy()

三、IOC 注解用法实战

1. 注解介绍

注解 作用
@Component 标记为组件,被扫描注册为 Bean
@Service 语义化的业务层组件
@Repository 语义化的数据访问层组件
@Controller 控制器组件
@Autowired 自动注入依赖
@Qualifier 配合 Autowired 指定具体 Bean
@Value 注入配置值
@PostConstruct Bean 初始化后执行
@PreDestroy Bean 销毁前执行

2. 示例代码

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

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

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

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/test")
    public String test() {
        userService.doBusiness();
        return "OK";
    }
}

四、底层原理简述(源码级理解)

1. 类扫描与 Bean 定义注册

Spring 启动时,会从 @ComponentScan 标注的包路径中扫描所有类,使用 ClassPathBeanDefinitionScanner 对类进行注册。

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(applicationContext);
scanner.scan("com.example.demo");

所有被 @Component@Service 等注解的类会被解析成 BeanDefinition 对象,并注册到 DefaultListableBeanFactory 中。

2. Bean 创建过程(AbstractAutowireCapableBeanFactory)

当容器调用 getBean() 方法时,最终会进入到 AbstractAutowireCapableBeanFactory#createBean() 方法中:

protected Object createBean(...) {
    // 1. 实例化对象(反射调用构造方法)
    Object bean = instantiateBean();

    // 2. 属性注入
    populateBean(beanName, mbd, instanceWrapper);

    // 3. 初始化前处理器调用
    applyBeanPostProcessorsBeforeInitialization(bean, beanName);

    // 4. 初始化方法执行(如 @PostConstruct)
    invokeInitMethods(beanName, bean, mbd);

    // 5. 初始化后处理器调用
    applyBeanPostProcessorsAfterInitialization(bean, beanName);

    return bean;
}

3. 注解注入原理

@Autowired 注解的处理由 AutowiredAnnotationBeanPostProcessor 完成,它实现了 BeanPostProcessor 接口。

  • 它在 postProcessPropertyValues 阶段通过反射扫描字段,找到有 @Autowired 注解的属性。
  • 根据属性类型从容器中获取 Bean,并注入到目标对象。
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
    Field field = ...; // 获取带 @Autowired 的字段
    Object value = beanFactory.getBean(field.getType());
    field.setAccessible(true);
    field.set(bean, value);
}

五、自定义注解实现模拟 IOC

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

public class MyContainer {
    private static Map<Class<?>, Object> beanMap = new HashMap<>();

    static {
        beanMap.put(UserDao.class, new UserDao());
        beanMap.put(UserService.class, new UserService());

        for (Object bean : beanMap.values()) {
            for (Field field : bean.getClass().getDeclaredFields()) {
                if (field.isAnnotationPresent(MyAutowired.class)) {
                    field.setAccessible(true);
                    try {
                        field.set(bean, beanMap.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static <T> T getBean(Class<T> clazz) {
        return (T) beanMap.get(clazz);
    }
}

六、总结

  • IOC 是 Spring 容器的核心,它将对象的创建和依赖注入“反转”给容器。
  • 开发中主要通过注解方式(@Component@Autowired)使用 IOC。
  • 源码中核心类如 BeanDefinition, BeanFactory, BeanPostProcessor 构成了完整的 IOC 生命周期。
  • 理解 IOC 原理,有助于我们解决 Bean 注入失败、循环依赖等问题。