Spring 源码解读:逐步实现 IoC 容器,深入理解 Spring 核心原理
前言
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() {
return beanClass;
}
/**
* 获取构造方法
* @return 构造方法
*/
public Constructor<?> getConstructor() {
return constructor;
}
/**
* 获取构造方法参数
* @return 构造方法参数
*/
public Object[] getConstructorArgs() {
return constructorArgs;
}
}
修改 SimpleBeanFactory 支持依赖注入
修改 SimpleBeanFactory
,使其在创建 Bean 时支持构造器注入。
private Object createBean(BeanDefinition beanDefinition) {
try {
// 使用指定的构造方法和参数创建 Bean 实例
return beanDefinition.getConstructor().newInstance(beanDefinition.getConstructorArgs());
} catch (Exception e) {
throw new RuntimeException("Failed to create bean", e);
}
}
测试依赖注入
public class IoCTest {
public static void main(String[] args) throws NoSuchMethodException {
SimpleBeanFactory beanFactory = new SimpleBeanFactory();
// 获取构造方法
Constructor<ExampleService> constructor = ExampleService.class.getConstructor(Dependency.class);
// 创建 BeanDefinition,并指定构造方法和参数
BeanDefinition beanDefinition = new BeanDefinition(ExampleService.class, constructor, new Object[]{new Dependency()});
// 注册 BeanDefinition
beanFactory.registerBeanDefinition("exampleService", beanDefinition);
// 获取 Bean 实例并调用方法
ExampleService exampleService = (ExampleService) beanFactory.getBean("exampleService");
exampleService.execute();
}
}
class ExampleService {
private Dependency dependency;
// 通过构造方法注入依赖
public ExampleService(Dependency dependency) {
this.dependency = dependency;
}
public void execute()
{
System.out.println("Dependency injected: " + (dependency != null));
}
}
class Dependency {
}
结果:程序将输出 Dependency injected: true
,说明依赖注入成功。
4. 第二阶段的流程图
第二步实现的类图
第三步:实现 Bean 的生命周期管理
1. 问题说明
在 Spring 框架中,Bean 通常需要在创建后进行一些初始化操作,比如设置一些属性、调用特定方法等。此外,在应用程序关闭时,Bean 可能需要进行一些清理工作。Spring 提供了 BeanPostProcessor
接口,用于在 Bean 的初始化前后进行自定义处理。因此,实现 Bean 的生命周期管理是 IoC 容器的一个重要功能。
2. 解决方案
为了支持 Bean 的生命周期管理,我们将引入 BeanPostProcessor
接口,并在 IoC 容器中添加相应的处理逻辑。BeanPostProcessor
允许在 Bean 初始化之前和之后执行自定义逻辑,如依赖注入、代理增强等。
3. 代码实现
添加 BeanPostProcessor
我们引入 BeanPostProcessor
接口,用于在 Bean 初始化前后进行处理。
public interface BeanPostProcessor {
/**
* 在 Bean 初始化之前进行处理
* @param bean Bean 实例
* @param beanName Bean 的名称
* @return 处理后的 Bean 实例
*/
Object postProcessBeforeInitialization(Object bean, String beanName);
/**
* 在 Bean 初始化之后进行处理
* @param bean Bean 实例
* @param beanName Bean 的名称
* @return 处理后的 Bean 实例
*/
Object postProcessAfterInitialization(Object bean, String beanName);
}
扩展 SimpleBeanFactory 支持生命周期管理
扩展 SimpleBeanFactory
,在创建 Bean 的过程中调用 BeanPostProcessor
的方法,支持生命周期管理。
public class SimpleBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
private Map<String, Object> singletonObjects = new HashMap<>();
private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
@Override
public Object getBean(String name) {
Object bean = singletonObjects.get(name);
if (bean == null) {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
bean = createBean(beanDefinition);
singletonObjects.put(name, bean);
}
return bean;
}
@Override
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
beanDefinitionMap.put(name, beanDefinition);
}
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.add(beanPostProcessor);
}
private Object createBean(BeanDefinition beanDefinition) {
try {
// 创建 Bean 实例
Object bean = beanDefinition.getConstructor().newInstance(beanDefinition.getConstructorArgs());
// 在初始化之前执行处理
for (BeanPostProcessor processor : beanPostProcessors) {
bean = processor.postProcessBeforeInitialization(bean, bean.getClass().getName());
}
// 在初始化之后执行处理
for (BeanPostProcessor processor : beanPostProcessors) {
bean = processor.postProcessAfterInitialization(bean, bean.getClass().getName());
}
return bean;
} catch (Exception e) {
throw new RuntimeException("Failed to create bean", e);
}
}
}
测试 Bean 的生命周期管理
我们可以通过实现 BeanPostProcessor
来测试 Bean 的生命周期管理。
public class IoCTest {
public static void main(String[] args) throws NoSuchMethodException {
SimpleBeanFactory beanFactory = new SimpleBeanFactory();
Constructor<ExampleService> constructor = ExampleService.class.getConstructor(Dependency.class);
BeanDefinition beanDefinition = new BeanDefinition(ExampleService.class, constructor, new Object[]{new Dependency()});
beanFactory.registerBeanDefinition("exampleService", beanDefinition);
// 添加 BeanPostProcessor
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("Before Initialization: " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("After Initialization: " + beanName);
return bean;
}
});
// 获取 Bean 实例并调用方法
ExampleService exampleService = (ExampleService) beanFactory.getBean("exampleService");
exampleService.execute();
}
}
结果:程序将输出以下内容,表明 Bean 的生命周期管理已经成功实现:
Before Initialization: ExampleService
After Initialization: ExampleService
Dependency injected: true
4. 第三阶段的流程图
第三步实现的类图
第四步:解决循环依赖问题
1. 问题说明
在复杂的应用中,可能会出现 Bean 之间的循环依赖。例如,A 依赖 B,B 又依赖 A。如果 IoC 容器不支持处理循环依赖,那么在创建 A 或 B 时,都会导致无限递归,最终导致栈溢出。为了解决这个问题,Spring IoC 容器引入了三级缓存机制,允许在创建过程中提前暴露 Bean 的引用,以解决循环依赖问题。
2. 解决方案
为了支持循环依赖,我们需要在 IoC 容器中引入三级缓存机制:
- 单例缓存(
singletonObjects
):用于存储完全初始化好的单例 Bean。 - 提前曝光的单例缓存(
earlySingletonObjects
):用于存储正在创建但尚未初始化完成的 Bean,用于解决循环依赖。 - Bean 定义缓存(
beanDefinitionMap
):用于存储 Bean 的配置信息。
在创建 Bean 时,先将 Bean 的早期引用放入 earlySingletonObjects
中,允许其他
Bean 引用它。待 Bean 完全创建后,将其从 earlySingletonObjects
移除,并放入 singletonObjects
中。
3. 代码实现
修改 SimpleBeanFactory 支持循环依赖
我们将通过三级缓存解决循环依赖问题。
public class SimpleBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
private Map<String, Object> singletonObjects = new HashMap<>();
private Map<String, Object> earlySingletonObjects = new HashMap<>();
private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
@Override
public Object getBean(String name) {
// 先从单例缓存中获取 Bean
Object bean = singletonObjects.get(name);
if (bean == null) {
// 从提前曝光的单例缓存中获取 Bean,处理循环依赖
bean = earlySingletonObjects.get(name);
if (bean == null) {
// 创建新的 Bean 实例
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
bean = createBean(name, beanDefinition);
singletonObjects.put(name, bean);
}
}
return bean;
}
@Override
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
beanDefinitionMap.put(name, beanDefinition);
}
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.add(beanPostProcessor);
}
private Object createBean(String beanName, BeanDefinition beanDefinition) {
try {
// 1. 创建 Bean 实例,但不完全初始化
Object bean = beanDefinition.getConstructor().newInstance(beanDefinition.getConstructorArgs());
// 2. 提前曝光这个半成品 Bean,处理循环依赖
earlySingletonObjects.put(beanName, bean);
// 3. 执行 BeanPostProcessor 的前置处理方法
for (BeanPostProcessor processor : beanPostProcessors) {
bean = processor.postProcessBeforeInitialization(bean, beanName);
}
// 4. 执行 BeanPostProcessor 的后置处理方法
for (BeanPostProcessor processor : beanPostProcessors) {
bean = processor.postProcessAfterInitialization(bean, beanName);
}
// 5. 移除早期曝光的 Bean,完成 Bean 的创建
earlySingletonObjects.remove(beanName);
return bean;
} catch (Exception e) {
throw new RuntimeException("Failed to create bean", e);
}
}
}
测试循环依赖
我们可以通过创建两个互相依赖的类来测试循环依赖的解决。
public class IoCTest {
public static void main(String[] args) throws NoSuchMethodException {
SimpleBeanFactory beanFactory = new SimpleBeanFactory();
// 注册 A 和 B 的 BeanDefinition
Constructor<A> constructorA = A.class.getConstructor(B.class);
beanFactory.registerBeanDefinition("A", new BeanDefinition(A.class, constructorA, new Object[]{null}));
Constructor<B> constructorB = B.class.getConstructor(A.class);
beanFactory.registerBeanDefinition("B", new BeanDefinition(B.class, constructorB, new Object[]{null}));
// 添加 BeanPostProcessor
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("Before Initialization: " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("After Initialization: " + beanName);
return bean;
}
});
// 获取 A 和 B 实例
A a = (A) beanFactory.getBean("A");
B b = (B) beanFactory.getBean("B");
a.execute();
b.execute();
}
}
class A {
private B b;
public A(B b) {
this.b = b;
}
public void execute() {
System.out.println("A is working with B: " + (b != null));
}
}
class B {
private A a;
public B(A a) {
this.a = a;
}
public void execute() {
System.out.println("B is working with A: " + (a != null));
}
}
结果:程序将输出以下内容,表明循环依赖问题已经成功解决:
Before Initialization: A
Before Initialization: B
After Initialization: A
After Initialization: B
A is working with B: true
B is working with A: true
4. 第四阶段的流程图
第四步实现的类图
二、Spring IoC 容器源码解析
通过上述实现,我们已经涵盖了 IoC 容器的核心功能。接下来,我们将对比 Spring 的实现,深入解析 Spring IoC 容器的设计与优化。
1. Spring IoC 容器架构与类图
Spring IoC 容器通过多个关键组件实现了强大的依赖注入、生命周期管理和循环依赖解决能力。以下是 Spring IoC 容器的核心类图:
2. 核心源码解析
DefaultListableBeanFactory
DefaultListableBeanFactory
是 Spring 的核心 IoC 容器实现类,结合了 Bean 注册与 Bean 实例化,支持依赖注入、循环依赖处理、Bean 作用域管理等复杂功能。以下是 DefaultListableBeanFactory
的部分关键源码:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanDefinitionMap.put(beanName, beanDefinition);
}
@Override
protected
Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
return doCreateBean(beanName, mbd, args);
}
}
核心方法解析:
getBean(String name)
: 获取 Bean 实例,处理依赖注入和懒加载。registerBeanDefinition(String name, BeanDefinition beanDefinition)
: 注册 BeanDefinition,将 Bean 定义信息保存到beanDefinitionMap
中。createBean(String beanName, RootBeanDefinition mbd, Object[] args)
: 创建 Bean 的核心方法,处理 Bean 的实例化、依赖注入、生命周期回调等。
AnnotationConfigApplicationContext
AnnotationConfigApplicationContext
是基于注解配置的 IoC 容器实现,通过扫描指定包路径下的类并解析其注解来注册 Bean。以下是 AnnotationConfigApplicationContext
的部分关键源码:
public class AnnotationConfigApplicationContext extends GenericApplicationContext
implements AnnotationConfigRegistry {
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public void register(Class<?>... annotatedClasses) {
this.reader.register(annotatedClasses);
}
public void scan(String... basePackages) {
this.scanner.scan(basePackages);
}
@Override
public void refresh() throws BeansException, IllegalStateException {
super.refresh();
}
}
3. 自定义实现与 Spring 源码的对比
-
生命周期管理:Spring 通过
BeanPostProcessor
实现了 Bean 的生命周期管理。我们在自定义实现中通过BeanPostProcessor
模拟了这一过程,体现了初始化前后逻辑处理。 -
循环依赖处理:Spring 采用三级缓存(
singletonObjects
、earlySingletonObjects
和singletonFactories
)解决循环依赖问题。在自定义实现中,我们通过earlySingletonObjects
模拟了循环依赖的解决机制。 -
依赖注入:Spring 支持构造器注入、Setter 注入等复杂的依赖注入方式。我们的自定义实现目前只支持简单的无参构造器注入。
三、总结
通过手动实现一个简化版的 IoC 容器,我们深入理解了 Spring IoC 容器的核心功能和设计思想。Spring 的 IoC 容器在解决循环依赖、管理 Bean 生命周期以及处理复杂依赖注入方面,展现了极高的灵活性和扩展性。理解这些原理有助于我们在日常开发中更好地使用 Spring 框架,也为我们理解更复杂的 Spring 机制打下坚实基础。
如果你觉得本篇内容对你有帮助,别忘了点赞、收藏和关注本专栏! 让我们一起深入学习 Spring 源码,提升编程技能,成为更优秀的开发者!