前言
Spring 框架的核心是 IoC(控制反转)容器,它负责管理应用程序中的对象(Bean)的创建、配置和依赖关系。对于初学者来说,理解 IoC 容器的工作原理是掌握 Spring 框架的关键。本篇文章将通过逐步实现一个简化版的 IoC 容器,帮助你逐步理解 Spring 是如何管理对象的,并最终实现一个接近 Spring 的 IoC 容器。
一、逐步实现 IoC 容器
第一步:实现最基本的 Bean 注册与获取
1. 问题说明
在任何 IoC 容器中,最基本的功能就是注册和获取 Bean。这是容器管理对象的核心功能。Bean 是 IoC 容器中的基本单元,它可以是任何 Java 对象,如服务、控制器、存储库等。IoC 容器需要能够存储这些 Bean 的定义,并在需要时创建并返回它们的实例。
2. 解决方案
我们将实现一个简单的 IoC 容器,通过 BeanFactory
接口定义基本的功能:注册和获取 Bean。SimpleBeanFactory
将实现这个接口,通过一个映射(Map
)来存储 Bean 的定义和实例。通过 getBean
方法获取 Bean 的实例,如果实例不存在则创建一个新实例并缓存起来。
3. 代码实现
定义 BeanFactory 接口
public interface BeanFactory {
/**
* 根据名称获取 Bean 实例
* @param name Bean 的名称
* @return Bean 实例
*/
Object getBean(String name);
/**
* 注册 Bean 定义
* @param name Bean 的名称
* @param beanDefinition Bean 定义对象
*/
void registerBeanDefinition(String name, BeanDefinition beanDefinition);
}
定义 BeanDefinition 类
BeanDefinition
类用于描述 Bean 的配置信息,例如它的类型。
public class BeanDefinition {
private Class<?> beanClass;
public BeanDefinition(Class<?> beanClass) {
this.beanClass = beanClass;
}
/**
* 获取 Bean 的类类型
* @return Bean 的类
*/
public Class<?> getBeanClass() {
return beanClass;
}
}
实现简单的 IoC 容器
我们实现一个简单的 SimpleBeanFactory
,可以注册和获取 Bean。
public class SimpleBeanFactory implements BeanFactory {
// 存储 Bean 定义的映射
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
// 存储单例 Bean 实例的映射
private Map<String, Object> singletonObjects = new HashMap<>();
@Override
public Object getBean(String name) {
// 先从缓存中获取单例 Bean
Object bean = singletonObjects.get(name);
if (bean == null) {
// 如果缓存中没有,则创建新的 Bean 实例
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
bean = createBean(beanDefinition);
singletonObjects.put(name, bean); // 放入缓存
}
return bean;
}
@Override
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
// 注册 Bean 定义
beanDefinitionMap.put(name, beanDefinition);
}
private Object createBean(BeanDefinition beanDefinition) {
try {
// 使用反射创建 Bean 实例
return beanDefinition.getBeanClass().newInstance();
} catch (Exception e) {
throw new RuntimeException("Failed to create bean", e);
}
}
}
测试简单的 IoC 容器
public class IoCTest {
public static void main(String[] args) {
// 创建 IoC 容器
SimpleBeanFactory beanFactory = new SimpleBeanFactory();
// 注册 Bean 定义
beanFactory.registerBeanDefinition("exampleService", new BeanDefinition(ExampleService.class));
// 获取 Bean 实例并调用方法
ExampleService exampleService = (ExampleService) beanFactory.getBean("exampleService");
exampleService.execute();
}
}
class ExampleService {
public void execute() {
System.out.println("Hello from ExampleService!");
}
}
结果:程序将输出 Hello from ExampleService!
,说明我们的简单 IoC 容器可以正常工作。
4. 第一阶段的流程图
第一步实现的类图
第二步:支持依赖注入
1. 问题说明
在实际应用中,Bean 之间往往存在依赖关系。例如,服务类可能依赖于另一个服务类或数据访问对象。如果 IoC 容器只支持简单的 Bean 创建,而不支持依赖注入,那么开发者就需要手动管理这些依赖,这会增加代码的复杂性。
2. 解决方案
为了解决这个问题,我们将扩展 IoC 容器,使其支持依赖注入。通过构造器注入的方式,我们可以在创建 Bean 时自动注入其依赖对象。我们需要扩展 BeanDefinition
类,以支持构造器注入。然后在创建 Bean 时,根据指定的构造方法和参数进行实例化。
3. 代码实现
扩展 BeanDefinition,支持构造器注入
我们扩展 BeanDefinition
类,使其支持构造器注入。
public class BeanDefinition {
private Class<?> beanClass;
private Constructor<?> constructor;
private Object[] constructorArgs;
public BeanDefinition(Class<?> beanClass, Constructor<?> constructor, Object[] constructorArgs) {
this.beanClass = beanClass;
this.constructor = constructor;
this.constructorArgs = constructorArgs;
}
/**
* 获取 Bean 的类类型
* @return Bean 的类
*/
public Class<?> getBeanClass()