导航
第 02 讲:IoC 容器基础
📖 本讲目标
- 理解 IoC(控制反转)的本质
- 设计 BeanFactory 核心接口
- 实现 ApplicationContext 基础功能
- 理解 Bean 的存储与管理机制
🎯 什么是 IoC?
IoC 的核心思想
IoC(Inversion of Control,控制反转) 是一种设计原则,它将对象的创建、依赖关系的管理从应用程序代码中转移到框架或容器中。
传统方式 vs IoC 方式
传统方式(控制权在程序员手中):
public class UserService {
private UserRepository userRepository;
public UserService() {
// 程序员自己创建依赖对象
this.userRepository = new UserRepository();
}
}
IoC 方式(控制权在容器中):
@Component
public class UserService {
@Autowired
private UserRepository userRepository;
// 容器负责创建和注入依赖
}
IoC 的优势
- 解耦:对象之间的依赖关系由容器管理,降低耦合度
- 灵活性:可以轻松替换实现类
- 可测试性:便于进行单元测试和模拟
- 统一管理:对象的生命周期由容器统一管理
🏗️ BeanFactory 接口设计
接口职责
BeanFactory 是 IoC 容器的核心接口,定义了访问容器中 Bean 的基本方法。
接口定义
创建 src/main/java/com/minispring/beans/factory/BeanFactory.java:
package com.minispring.beans.factory;
/**
* BeanFactory 接口
* IoC 容器的核心接口,定义了访问容器中 Bean 的基本方法
*/
public interface BeanFactory {
/**
* 根据 Bean 名称获取 Bean 实例
* @param name Bean 的名称
* @return Bean 实例对象
* @throws Exception 如果找不到指定名称的 Bean 或创建过程中发生异常
*/
Object getBean(String name) throws Exception;
/**
* 根据 Bean 名称和指定类型获取 Bean 实例
* @param name Bean 的名称
* @param requiredType 期望的 Bean 类型
* @param <T> Bean 的泛型类型
* @return 指定类型的 Bean 实例
* @throws Exception 如果找不到指定名称的 Bean 或类型不匹配
*/
<T> T getBean(String name, Class<T> requiredType) throws Exception;
/**
* 根据类型获取 Bean 实例
* @param requiredType Bean 的类型
* @param <T> Bean 的泛型类型
* @return 指定类型的 Bean 实例
* @throws Exception 如果找不到指定类型的 Bean
*/
<T> T getBean(Class<T> requiredType) throws Exception;
/**
* 判断容器中是否包含指定名称的 Bean
* @param name Bean 的名称
* @return 如果存在返回 true,否则返回 false
*/
boolean containsBean(String name);
/**
* 判断指定名称的 Bean 是否为单例模式
* @param name Bean 的名称
* @return 如果是单例返回 true,否则返回 false
*/
boolean isSingleton(String name);
/**
* 判断指定名称的 Bean 是否为原型模式
* @param name Bean 的名称
* @return 如果是原型返回 true,否则返回 false
*/
boolean isPrototype(String name);
/**
* 获取指定名称 Bean 的类型
* @param name Bean 的名称
* @return Bean 的 Class 类型
*/
Class<?> getType(String name);
}
接口方法说明
- getBean(String name):最基本的 Bean 获取方法
- getBean(String name, Class):带类型检查的获取方法
- getBean(Class):按类型获取,支持自动匹配
- containsBean(String):检查 Bean 是否存在
- isSingleton/isPrototype:查询 Bean 的作用域
- getType(String):获取 Bean 的类型信息
🏭 ApplicationContext 核心实现
设计思路
ApplicationContext 是 BeanFactory 的实现类,也是整个框架的核心。它需要:
- 存储 Bean 定义:使用 Map 存储 BeanDefinition
- 缓存单例 Bean:使用 Map 缓存已创建的单例 Bean
- 管理 Bean 生命周期:创建、初始化、销毁
基础实现
创建 src/main/java/com/minispring/context/ApplicationContext.java:
package com.minispring.context;
import com.minispring.beans.factory.BeanFactory;
import com.minispring.beans.factory.config.BeanDefinition;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* 应用上下文,IoC 容器的核心实现
*/
public class ApplicationContext implements BeanFactory {
// ==================== 核心存储结构 ====================
/**
* 存储所有 BeanDefinition(Bean 的元数据)
* Key: beanName, Value: BeanDefinition
*/
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
/**
* 单例 Bean 缓存池(一级缓存)
* Key: beanName, Value: Bean 实例
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
/**
* 正在创建中的 Bean 集合,用于检测循环依赖
*/
private final Set<String> singletonsCurrentlyInCreation = ConcurrentHashMap.newKeySet();
// ==================== BeanDefinition 管理 ====================
/**
* 注册 BeanDefinition
* @param beanName Bean 名称
* @param beanDefinition Bean 定义
*/
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
if (beanDefinitionMap.containsKey(beanName)) {
throw new RuntimeException("Bean 名称重复: " + beanName);
}
beanDefinitionMap.put(beanName, beanDefinition);
}
/**
* 获取 BeanDefinition
* @param beanName Bean 名称
* @return BeanDefinition
*/
public BeanDefinition getBeanDefinition(String beanName) {
return beanDefinitionMap.get(beanName);
}
// ==================== Bean 获取(核心方法) ====================
@Override
public Object getBean(String beanName) throws Exception {
// 1. 获取 BeanDefinition
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) {
throw new RuntimeException("找不到 Bean: " + beanName);
}
// 2. 根据作用域决定返回策略
if (beanDefinition.isSingleton()) {
// 单例模式:从缓存获取或创建
return getSingleton(beanName, beanDefinition);
} else {
// 原型模式:每次都创建新实例
return createBean(beanName, beanDefinition);
}
}
@Override
public <T> T getBean(String beanName, Class<T> requiredType) throws Exception {
Object bean = getBean(beanName);
if (requiredType != null && !requiredType.isInstance(bean)) {
throw new RuntimeException("Bean 类型不匹配: " + beanName);
}
return (T) bean;
}
@Override
public <T> T getBean(Class<T> requiredType) throws Exception {
// 遍历所有 BeanDefinition,查找类型匹配的 Bean
String matchedBeanName = null;
for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = entry.getValue();
if (requiredType.isAssignableFrom(beanDefinition.getBeanClass())) {
if (matchedBeanName != null) {
throw new RuntimeException("找到多个类型为 " + requiredType.getName() +
" 的 Bean: " + matchedBeanName + ", " + beanName);
}
matchedBeanName = beanName;
}
}
if (matchedBeanName == null) {
throw new RuntimeException("找不到类型为 " + requiredType.getName() + " 的 Bean");
}
return getBean(matchedBeanName, requiredType);
}
@Override
public boolean containsBean(String beanName) {
return beanDefinitionMap.containsKey(beanName);
}
@Override
public boolean isSingleton(String name) {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new RuntimeException("找不到 Bean: " + name);
}
return beanDefinition.isSingleton();
}
@Override
public boolean isPrototype(String name) {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new RuntimeException("找不到 Bean: " + name);
}
return beanDefinition.isPrototype();
}
@Override
public Class<?> getType(String name) {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new RuntimeException("找不到 Bean: " + name);
}
return beanDefinition.getBeanClass();
}
// ==================== 单例 Bean 管理 ====================
/**
* 获取单例 Bean(从缓存或创建)
* @param beanName Bean 名称
* @param beanDefinition Bean 定义
* @return Bean 实例
*/
private Object getSingleton(String beanName, BeanDefinition beanDefinition) throws Exception {
synchronized (singletonObjects) {
// 1. 先从缓存中获取
Object singletonObject = singletonObjects.get(beanName);
if (singletonObject != null) {
return singletonObject;
}
// 2. 创建 Bean 实例
singletonObject = createBean(beanName, beanDefinition);
// 3. 放入缓存
singletonObjects.put(beanName, singletonObject);
return singletonObject;
}
}
// ==================== Bean 创建 ====================
/**
* 创建 Bean 实例(核心流程)
* @param beanName Bean 名称
* @param bd Bean 定义
* @return Bean 实例
*/
private Object createBean(String beanName, BeanDefinition bd) throws Exception {
// 1. 检查循环依赖
if (singletonsCurrentlyInCreation.contains(beanName)) {
throw new RuntimeException("检测到循环依赖: " + beanName);
}
// 2. 标记为正在创建
singletonsCurrentlyInCreation.add(beanName);
try {
// 3. 使用反射创建实例(暂时使用无参构造函数)
Object bean = bd.getBeanClass().getDeclaredConstructor().newInstance();
// TODO: 后续将实现依赖注入和初始化回调
return bean;
} finally {
// 4. 移除创建中标记
singletonsCurrentlyInCreation.remove(beanName);
}
}
// ==================== 辅助方法 ====================
/**
* 获取所有 Bean 名称
* @return Bean 名称集合
*/
public Set<String> getBeanDefinitionNames() {
return beanDefinitionMap.keySet();
}
/**
* 获取 Bean 数量
* @return Bean 数量
*/
public int getBeanDefinitionCount() {
return beanDefinitionMap.size();
}
}
📦 BeanDefinition 基础
在实现完整的 BeanDefinition 之前,我们先创建一个简化版本:
创建 src/main/java/com/minispring/beans/factory/config/BeanDefinition.java:
package com.minispring.beans.factory.config;
/**
* BeanDefinition 类
* 存储 Bean 的元数据信息,是 IoC 容器管理 Bean 的核心数据结构
*/
public class BeanDefinition {
// Bean 的 Class 类型,用于反射创建实例
private Class<?> beanClass;
// Bean 在容器中的唯一名称
private String beanName;
// Bean 的作用域:singleton(单例)或 prototype(原型)
private String scope = "singleton"; // 默认单例
/**
* 构造函数
*/
public BeanDefinition() {
}
/**
* 构造函数
* @param beanClass Bean 的 Class 类型
*/
public BeanDefinition(Class<?> beanClass) {
this.beanClass = beanClass;
}
// ==================== Getter 和 Setter 方法 ====================
public Class<?> getBeanClass() {
return beanClass;
}
public void setBeanClass(Class<?> beanClass) {
this.beanClass = beanClass;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
/**
* 判断是否为单例模式
* @return true 表示单例
*/
public boolean isSingleton() {
return "singleton".equals(scope);
}
/**
* 判断是否为原型模式
* @return true 表示原型
*/
public boolean isPrototype() {
return "prototype".equals(scope);
}
}
🧪 简单测试
创建一个简单的测试类验证基础功能:
package com.minispring.demo;
import com.minispring.beans.factory.config.BeanDefinition;
import com.minispring.context.ApplicationContext;
public class SimpleTest {
public static void main(String[] args) throws Exception {
ApplicationContext context = new ApplicationContext();
// 手动注册一个 Bean
BeanDefinition bd = new BeanDefinition();
bd.setBeanClass(String.class);
bd.setBeanName("testBean");
bd.setScope("singleton");
context.registerBeanDefinition("testBean", bd);
// 获取 Bean
Object bean = context.getBean("testBean");
System.out.println("获取到 Bean: " + bean);
System.out.println("Bean 类型: " + context.getType("testBean"));
System.out.println("是否为单例: " + context.isSingleton("testBean"));
}
}
📝 本讲总结
本讲我们完成了:
- ✅ 理解了 IoC 的核心思想
- ✅ 设计了 BeanFactory 核心接口
- ✅ 实现了 ApplicationContext 基础功能
- ✅ 创建了 BeanDefinition 数据结构
- ✅ 实现了单例 Bean 的缓存机制
- ✅ 实现了循环依赖检测的基础框架
🎯 关键点回顾
- IoC 容器:负责管理对象的创建和生命周期
- BeanFactory:定义了容器的基本操作接口
- ApplicationContext:容器的核心实现
- BeanDefinition:存储 Bean 的元数据信息
- 单例缓存:使用 Map 缓存单例 Bean,提高性能
🚀 下一讲预告
在下一讲中,我们将完善 BeanDefinition 的设计,并实现 Bean 的注册机制,包括:
- BeanDefinition 的完整属性
- Bean 名称生成策略
- Bean 注册流程
准备好了吗?让我们继续 第 03 讲:Bean 定义与注册!
思考题:
- 为什么使用 ConcurrentHashMap 而不是普通的 HashMap?
- 单例 Bean 缓存的作用是什么?
- 循环依赖检测是如何工作的?
