导读:很想仔细了解 Spring IOC/AOP 框架,但发现 Spring 源码不仅长且难以阅读。今天搜索时发现 github 上有一个高星重制 Spring IOC/AOP 框架的项目——Tiny-Spring,粗略阅读一遍大概30分钟,仔细研究一番很有收获,特此记录。
us.codecraft.tinyioc
下有三个包,aop
beans
context
,aop
毫无疑问是对面向切面编程的实现,beans
和 context
用于实现 IOC
框架。
ApplicationContext context = new classPathXmlApplicationContext('ioc.xml');
说明:创建上下文对象,程序入口。继承关系:[I]BeanFactory
<--[I]ApplicationContext
<-- [AbsC]AbstractApplicationContext
<-- [C]ClassPathXmlApplicationContext
this(configLocation, new AutowireCapableBeanFactory());
调用默认构造方法。
Beanfactory
系列继承关系:
[I]BeanFactory
<-- [AbsC]AbstractBeanFactory
<-- [C]AutowireCapableBeanFactory
super(beanFactory);
this.configLocation = configLocation;
refresh();
【返回3】调用另一个构造方法。
第一句。调用父级构造方法,具体:this.beanFactory = beanFactory;
将刚创建的beanFactory赋值到protected属性中。
第二句。xml文件路径赋值给自身属性。
第三句。刷新,方法定义在父级中,被子级继承。具体操作:
xxxxxxxxxx
//[AbsC]AbstarctApplicationContext
public void refresh() throws Exception {
loadBeanDefinitions(beanFactory);
registerBeanPostProcessors(beanFactory);
onRefresh();
}
【返回 4】先看第一句loadBeanDefinitions
,方法原型在AbstarctApplicationContext
中,是抽象方法,此方法在子类被 override:
xxxxxxxxxx
protected void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
}
【返回5】步骤1,创建ResourceLoader
,并以此为参数创建XmlBeanDefinitionReader
。
ResourceLoader
定义如下,其唯一方法用于根据文件位置读取资源。
xpackage us.codecraft.tinyioc.beans.io;
import java.net.URL;
public class ResourceLoader {
public Resource getResource(String location){
URL resource = this.getClass().getClassLoader().getResource(location);
return new UrlResource(resource);
}
}
XmlBeanDefinitionReader
的构造方法:
xxxxxxxxxx
public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
super(resourceLoader);
}
XmlBeanDefinitionReader
的父类是 AbstractBeanDefinitionReader
,其构造方法:
xxxxxxxxxx
protected AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {
this.registry = new HashMap<String, BeanDefinition>();
this.resourceLoader = resourceLoader;
}
其中 registry
是一个 HashMap
,用于保存 bean
名(具体指xml中的id属性)和它的定义 beanDefinition
。
beanDefinition
具体如下:
xxxxxxxxxx
public class BeanDefinition {
private Object bean;
private Class beanClass;
private String beanClassName;
private PropertyValues propertyValues = new PropertyValues();
//以下省略getter和setter
}
【返回5】现在负责读取Xml的对象准备好了,调用 loadBeanDefinition
,然后调用接下来的一连串方法:
xxxxxxxxxx
public void loadBeanDefinitions(String location) throws Exception {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinitions(inputStream);
}
protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
registerBeanDefinitions(doc);
inputStream.close();
}
public void registerBeanDefinitions(Document doc) {
Element root = doc.getDocumentElement();
parseBeanDefinitions(root);
}
protected void parseBeanDefinitions(Element root) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
processBeanDefinition(ele);
}
}
}
protected void processBeanDefinition(Element ele) {
String name = ele.getAttribute("id");
String className = ele.getAttribute("class");
BeanDefinition beanDefinition = new BeanDefinition();
processProperty(ele, beanDefinition);
beanDefinition.setBeanClassName(className);
getRegistry().put(name, beanDefinition);
}
private void processProperty(Element ele, BeanDefinition beanDefinition) {
NodeList propertyNode = ele.getElementsByTagName("property");
for (int i = 0; i < propertyNode.getLength(); i++) {
Node node = propertyNode.item(i);
if (node instanceof Element) {
Element propertyEle = (Element) node;
String name = propertyEle.getAttribute("name");
String value = propertyEle.getAttribute("value");
if (value != null && value.length() > 0) {
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
} else {
String ref = propertyEle.getAttribute("ref");
if (ref == null || ref.length() == 0) {
throw new IllegalArgumentException("Configuration problem: <property> element for property '"
+ name + "' must specify a ref or value");
}
BeanReference beanReference = new BeanReference(ref);
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));
}
}
}
}
初步读下来,概括如下:读取xml文件,创建xml解析树,把xml中的元素解析后注册到 registry
中。
【返回5】
xxxxxxxxxx
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
for-each 循环遍历哈希表 registry
,对于其中的每个 key-value
对,在 beanFactory
中预注册 bean
【返回8】
这里需要提一下,AbstractBeanFactory
包含三个重要变量:
xxxxxxxxxx
//类似factory中的registry
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
//bean name...
private final List<String> beanDefinitionNames = new ArrayList<String>();
//后置处理器
private List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
调用 registerBeanDefinition
,类似把半成品 registry
搬到了 context
中。
xxxxxxxxxx
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
beanDefinitionMap.put(name, beanDefinition);
beanDefinitionNames.add(name);
}
【返回4】
bean
信息处理完毕,调用 onRefresh()
:
xxxxxxxxxx
//AbstractApplicationContext
protected void onRefresh() throws Exception{
beanFactory.preInstantiateSingletons();
}
xxxxxxxxxx
//AbstractBeanFactory
public void preInstantiateSingletons() throws Exception {
for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
String beanName = (String) it.next();
getBean(beanName);
}
}
xxxxxxxxxx
//AbstractBeanFactory
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beanDefinition.getBean();
if (bean == null) {
bean = doCreateBean(beanDefinition);
bean = initializeBean(bean, name);
beanDefinition.setBean(bean);
}
return bean;
}
试图取得 bean
,但由于 bean
未创建,因此得到 null
,调用创建 bean
的方法:
至于为什么要先 getBean,是因为onFresh可以在后面被反复调用(初始化时固然得到的 bean 全为 null),且这是在创建 singleton,onFresh 方法如果在初始化完毕后再次调用,如果没有 getBean,则新创建出的 bean 覆盖原来的 bean,就产生了矛盾。
【返回10】
xxxxxxxxxx
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
Object bean = createBeanInstance(beanDefinition);
beanDefinition.setBean(bean);
applyPropertyValues(bean, beanDefinition);
return bean;
}
xxxxxxxxxx
protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
return beanDefinition.getBeanClass().newInstance();
}
xxxxxxxxxx
protected Object initializeBean(Object bean, String name) throws Exception {
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessBeforeInitialization(bean, name);
}
// TODO:call initialize method
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessAfterInitialization(bean, name);
}
return bean;
}
先创建 bean ,注册到 beanDefinitionMap
然后按序调用 beanPostProcessor
。
至此 applicationContext
的 Bean 管理已经建立起来,可以做到随时取用了。
ApplicationContext
,在此过程中创建 BeanFactory
的子类作为它的私有属性。beanFactory
创建 xml
解析对象,解析指定路径的xml
,并将信息注册到解析器的哈希表 registy
中。registry
信息搬入 beanFactory
的总管理对象 beanDefinitionMap
中。Bean
并调用后置处理器。context
中可调用 getBean
连接到 beanFactory
,并拿到 Bean
。applicationContext
虽然能对 bean 进行相关操作,但它只不过是一个存放了 beanFactory
对象的平台, 而 beanFactory
则是负责解析 bean,生产 bean 等幕后工作。可以直接创建 applicationContext
管理 bean,也可以创建 beanFactory
管理,一般选择前者。