本文针对的是icomac-spring项目,是自己重现了tianxiaono的仿写toy-spring项目,最开始的版本是黄亿华前辈实现的 tiny-spring ,该项目时间节点是 2014.1
具体参考:自己动手实现的 Spring IOC 和 AOP - 下篇
xml 的解析
BeanFactory 初始化时,会根据传入的 xml 配置文件路径加载并解析配置文件。但是加载和解析 xml 配置文件这种脏活累活,BeanFactory 可不太愿意干,它只想高冷的管理容器中的 bean。于是 BeanFactory 将加载和解析配置文件的任务委托给专职人员 BeanDefinitionReader 的实现类 XmlBeanDefinitionReader 去做。那么 XmlBeanDefinitionReader 具体是怎么做的呢?XmlBeanDefinitionReader 做了如下几件事情:
- 将 xml 配置文件加载到内存中
- 获取根标签下所有的标签
- 遍历获取到的标签列表,并从标签中读取 id,class 属性
- 创建 BeanDefinition 对象,并将刚刚读取到的 id,class 属性值保存到对象中
- 遍历标签下的标签,从中读取属性值,并保持在 BeanDefinition 对象中
- 将 <id, BeanDefinition> 键值对缓存在 Map 中,留作后用
- 重复3、4、5、6步,直至解析结束
BeanFactory
BeanFactory 的生命流程,也就是 IOC 容器的生命流程
- BeanFactory 加载 Bean 配置文件,将读到的 Bean 配置封装成 BeanDefinition 对象
- 将封装好的 BeanDefinition 对象注册到 BeanDefinition 容器中
- 注册 BeanPostProcessor 相关实现类到 BeanPostProcessor 容器中
- BeanFactory 进入就绪状态
- 外部调用 BeanFactory 的 getBean(String name) 方法,BeanFactory 着手实例化相应的 bean
- 重复步骤 3 和 4,直至程序退出,BeanFactory 被销毁
注册BeanPostProcessor
XmlBeanDefinitionReader 在完成解析工作后,BeanFactory 会将它解析得到的 <id, BeanDefinition> 键值对注册到自己的 beanDefinitionMap 中。
BeanFactory 注册好 BeanDefinition 后,就立即开始注册 BeanPostProcessor 相关实现类。这个过程比较简单:
- 根据 BeanDefinition 记录的信息,寻找所有实现了 BeanPostProcessor 接口的类。
- 实例化 BeanPostProcessor 接口的实现类
- 将实例化好的对象放入 List中
- 重复2、3步,直至所有的实现类完成注册
getBean 过程解析
在完成了 xml 的解析、BeanDefinition 的注册以及 BeanPostProcessor 的注册过程后。BeanFactory 初始化的工作算是结束了,此时 BeanFactory 处于就绪状态,等待外部程序的调用。
外部程序一般都是通过调用 BeanFactory 的 getBean(String name) 方法来获取容器中的 bean。BeanFactory 具有延迟实例化 bean 的特性,也就是等外部程序需要的时候,才实例化相关的 bean。这样做的好处是比较显而易见的,第一是提高了 BeanFactory 的初始化速度,第二是节省了内存资源。
- 实例化bean对象
- 设置对象属性
- 检查Aware相关接口并设置相关依赖
- BeanPostProcessor前置处理
- 检查是否是InitializingBean以决定是否调用afterPropertiesSet方法
- 检查是否配置有自定义的init-method
- BeanPostProcessor后置处理
- 注册必要的Destruction相关回调接口
- 使用中
- 是否实现DisposableBean接口
- 是否配置有自定义的destroy方法
对于icomac-spring项目
- 实例化 bean 对象,类似于 new XXObject()
- 将配置文件中配置的属性填充到刚刚创建的 bean 对象中
- 检查 bean 对象是否实现了 Aware 一类的接口,如果实现了则把相应的依赖设置到 bean 对象中。icomac-spring 目前仅对 BeanFactoryAware 接口实现类提供了支持
- 调用 BeanPostProcessor 前置处理方法,即 postProcessBeforeInitialization(Object bean, String beanName)
- 调用 BeanPostProcessor 后置处理方法,即 postProcessAfterInitialization(Object bean, String beanName)
- bean 对象处于就绪状态,可以使用了
测试类
package com.icomac.spring.ioc;
import com.icomac.spring.Car;
import com.icomac.spring.HelloService;
import com.icomac.spring.Wheel;
import com.icomac.spring.ioc.xml.XmlBeanFactory;
import org.junit.Test;
/**
* Created by icomac on 19/4/10.
*/
public class XmlBeanFactoryTest {
@Testd
public void getBean() throws Exception {
System.out.println("--------- IOC test ----------");
String location = getClass().getClassLoader().getResource("toy-spring.xml").getFile();
XmlBeanFactory bf = new XmlBeanFactory(location);
Wheel wheel = (Wheel) bf.getBean("wheel");
System.out.println(wheel);
Car car = (Car) bf.getBean("car");
System.out.println(car);
}
}
最后结果