导读:很想仔细了解 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]AbstarctApplicationContextpublic 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 的构造方法:
xxxxxxxxxxpublic XmlBeanDefinitionReader(ResourceLoader resourceLoader) { super(resourceLoader);}XmlBeanDefinitionReader 的父类是 AbstractBeanDefinitionReader,其构造方法:
xxxxxxxxxxprotected AbstractBeanDefinitionReader(ResourceLoader resourceLoader) { this.registry = new HashMap<String, BeanDefinition>(); this.resourceLoader = resourceLoader;}其中 registry 是一个 HashMap ,用于保存 bean 名(具体指xml中的id属性)和它的定义 beanDefinition。
beanDefinition 具体如下:
xxxxxxxxxxpublic 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】
xxxxxxxxxxfor (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中的registryprivate 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 中。
xxxxxxxxxxpublic void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception { beanDefinitionMap.put(name, beanDefinition); beanDefinitionNames.add(name);}【返回4】
bean 信息处理完毕,调用 onRefresh():
xxxxxxxxxx//AbstractApplicationContextprotected void onRefresh() throws Exception{ beanFactory.preInstantiateSingletons();}xxxxxxxxxx//AbstractBeanFactorypublic void preInstantiateSingletons() throws Exception { for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) { String beanName = (String) it.next(); getBean(beanName); }}xxxxxxxxxx//AbstractBeanFactorypublic 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】
xxxxxxxxxxprotected Object doCreateBean(BeanDefinition beanDefinition) throws Exception { Object bean = createBeanInstance(beanDefinition); beanDefinition.setBean(bean); applyPropertyValues(bean, beanDefinition); return bean;}xxxxxxxxxxprotected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception { return beanDefinition.getBeanClass().newInstance(); }xxxxxxxxxxprotected 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 管理,一般选择前者。