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 生命周期流程:
- 实例化 Bean
- 属性注入
- 调用 BeanNameAware、BeanFactoryAware 等 Aware 接口
- 调用 BeanPostProcessor 的
postProcessBeforeInitialization
- 初始化方法(如
@PostConstruct
) - 调用 BeanPostProcessor 的
postProcessAfterInitialization
- Bean 就绪使用
- 容器关闭时调用
@PreDestroy
或DisposableBean.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 注入失败、循环依赖等问题。