面向对象手写 Spring IoC - Bean 的实例化与依赖注入

前文:
面向过程手写 Spring IoC
手写 Spring IoC 模块设计
手写 Spring IoC 容器 —— BeanDefinition 加载与解析

手写 Spring IoC 容器 —— Bean 的实例化与依赖注入

引言

在 Spring IoC 容器的核心功能中,Bean 的实例化与依赖注入至关重要。

本文将实现 Spring IoC 的实例创建部分:

  1. 定位并加载XML资源文件
  2. 创建Document文档对象
  3. 解析Document文档
  4. 解析Document中的Bean标签
  5. 注册BeanDefinition

1. BeanFactory 设计

BeanFactory 是 Spring IoC 容器的顶级接口,定义了 getBean 方法。

1
2
3
4
5
6
7
8
9
/
* Spring 容器的顶级接口
*/
public interface BeanFactory {
/
* 根据 bean 名称获取实例
*/
Object getBean(String beanName);
}

设计思路:

  • 统一所有 IoC 容器的基本行为。
  • 允许不同的 BeanFactory 实现,例如 ListableBeanFactoryAutowireCapableBeanFactory

2. 抽象工厂 AbstractBeanFactory

AbstractBeanFactory 继承 DefaultSingletonBeanRegistry,负责 Bean 的获取逻辑。
抽象了getBean 方法逻辑

  1. 先从单例Bean的map集合中查找,如果找到直接返回
  2. 不存在,则从Bean的定义信息集合中查找对应的BeanDefinition
  3. 判断该Bean是单例还是多例
  4. 如果是单例,创建Bean实例并存入单例Bean的map集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String beanName) {
Object singletonObject = getSingleton(beanName);
if (singletonObject != null){
return singletonObject;
}

BeanDefinition bd = getBeanDefinition(beanName);
if (bd == null){
return null;
}

if (bd.isSingleton()) {
singletonObject = createBean(bd);
addSingleton(beanName, singletonObject);
} else if (bd.isPrototype()) {
singletonObject = createBean(bd);
}

return singletonObject;
}

protected abstract BeanDefinition getBeanDefinition(String beanName);
protected abstract Object createBean(BeanDefinition bd);
}

设计思路:

  • 模板方法模式:
    • getBean 是 模板方法,抽象了 Bean 的获取流程,具体实现由子类完成。
    • getBeanDefinition 由子类实现,不同 BeanFactory 可以有不同的 BeanDefinition 解析方式。
    • createBean 由子类实现,不同 BeanFactory 可以有不同的 Bean 创建方式。
  • 单例管理:
    • 先检查 singletonObjects 缓存,避免重复创建 Bean。
    • 如果是 单例,则创建后存入 singletonObjects
    • 如果是 多例,则每次调用 getBean 都创建新的实例。

3. Bean 的创建与依赖注入

AbstractAutowireCapableBeanFactory 负责 实例化 Bean、依赖注入、初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object createBean(BeanDefinition bd) {
Object bean = null;
try {
// 5.1 Bean 实例化
bean = createBeanInstance(bd);
// 5.2 依赖注入
populateBean(bean, bd);
// 5.3 初始化 Bean
initializeBean(bean, bd);
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}

设计思路:

  • createBeanInstance:通过 反射 创建 Bean 实例。
  • populateBean:解析 property 属性并注入。
  • initializeBean:执行 init-method 方法。

3.1 Bean 实例化

1
2
3
private Object createBeanInstance(BeanDefinition bd) throws Exception {
return ReflectUtils.createBean(bd.getClazzType());
}

为什么不直接 new

  • Bean 可能需要 通过工厂方法创建。
  • Bean 可能 代理对象(如 AOP 代理)。
  • 解耦实例化方式,可以扩展 多种创建策略。

3.2 依赖注入

1
2
3
4
5
6
7
8
9
10
11
12
private void populateBean(Object bean, BeanDefinition bd) throws Exception {
List<PropertyValue> propertyValues = bd.getPropertyValues();
for (PropertyValue pv : propertyValues) {
String name = pv.getName();
Object value = pv.getValue();

BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this);
Object valueToUse = valueResolver.resolveValue(value);

ReflectUtils.setProperty(bean, name, valueToUse);
}
}

设计思路:

  • 解析 propertyvalueref
  • 通过 ReflectUtils 反射注入属性。

3.3 初始化 Bean

1
2
3
4
5
6
7
8
9
private void initializeBean(Object bean, BeanDefinition bd) throws Exception {
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
invokeInitMethod(bean, bd);
}

设计思路:

  • 处理 Aware 接口,如 BeanFactoryAware
  • 执行 InitializingBeanafterPropertiesSet 方法。
  • 调用 init-method 指定的初始化方法。
1
2
3
4
5
6
private void invokeInitMethod(Object bean, BeanDefinition bd) throws Exception {
String initMethod = bd.getInitMethod();
if (initMethod != null) {
ReflectUtils.invokeMethod(bean, initMethod);
}
}

4. 单例管理

Spring 通过 SingletonBeanRegistry 维护单例 Bean。

1
2
3
4
public interface SingletonBeanRegistry {
Object getSingleton(String beanName);
void addSingleton(String beanName, Object bean);
}

DefaultSingletonBeanRegistry 实现了 SingletonBeanRegistry

1
2
3
4
5
6
7
8
9
10
11
12
13
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
private Map<String, Object> singletonObjects = new HashMap<>();

@Override
public Object getSingleton(String beanName) {
return this.singletonObjects.get(beanName);
}

@Override
public void addSingleton(String beanName, Object bean) {
this.singletonObjects.put(beanName, bean);
}
}

设计思路:

  • 维护 singletonObjects 单例缓存池。
  • 通过 线程安全的方式 存储单例 Bean(可扩展双重检查锁)。

5. BeanDefinition 注册

Spring 基本容器。
底层操作 BeanDefinition Map 的核心实现类,实现了 BeanDefinitionRegistry 接口,负责注册或获取 BeanDefinition。
同时继承了 AbstractAutowireCapableBeanFactory 抽象工厂。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry , ListableBeanFactory {
private Map<String,BeanDefinition> beanDefinitions = new HashMap<>();

@Override
public BeanDefinition getBeanDefinition(String beanName) {
return this.beanDefinitions.get(beanName);
}

@Override
public List<BeanDefinition> getBeanDefinitions() {
List<BeanDefinition> beanDefinitionList = new ArrayList<>();
for (BeanDefinition bd : beanDefinitions.values()){
beanDefinitionList.add(bd);
}
return beanDefinitionList;
}

@Override
public void registerBeanDefinition(String beanName, BeanDefinition bd) {
this.beanDefinitions.put(beanName,bd);
}

/**
*
* @param type 父类型
* @param <T>
* @return
*/
@Override
public <T> List<T> getBeansByType(Class type) {
List<T> results = new ArrayList<>();

List<BeanDefinition> beanDefinitions = getBeanDefinitions();
for (BeanDefinition bd : beanDefinitions) {
// 容器类当前类的类型
Class<?> clazzType = bd.getClazzType();

if (type.isAssignableFrom(clazzType)){
results.add((T) getBean(bd.getBeanName()));
}
}
return results;
}

@Override
public List<String> getBeanNamesByType(Class type) {
return null;
}
}