ApplicationContext context = new FileSystemXmlApplicationContext("f:/workspace/spring3/demo/applicationContext.xml");
新建一个容器,看看后面干了啥
FileSystemXmlApplicationContext(AbstractApplicationContext).refresh() line: 395
调用父类refresh,这个方法很重要……就是刷新容器
……
FileSystemXmlApplicationContext(AbstractXmlApplicationContext).loadBeanDefinitions(XmlBeanDefinitionReader) line: 126 ——reader.loadBeanDefinitions(configLocations);
load bean定义
XmlBeanDefinitionReader.loadBeanDefinitions(Resource) line: 302
我们用String指定了xml配置文件的路径,spring要将其封装到Resource方便io,这里的Resource指的就是我们的配置
之后经过各种读取,把Resource读入,其实就是一个xml文档,又封装为Document实例,XmlBeanDefinitionReader.registerBeanDefinitions(Document, Resource) line: 493
接下来就一个节点一个节点解析就可以了,其中bean节点的解析值得深入
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element, BeanDefinitionParserDelegate) line: 133
if (delegate.isDefaultNamespace(namespaceUri)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
上面这段代码的意思是,document中的element如果namespace是spring的(就是spring自己的)那么调某个方法,如果不是(就是自定义的),那就调另外的方法。意思就是说我们其实可以自定义spring的节点,现在先看bean节点的解析。
DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element, BeanDefinitionParserDelegate) 看这个方法第一行:
追踪到下面这个方法,返回一个BeanDefinitionHolder,它是Bean定义的Holder(它包含了一个指向某BeanDefinition实例的引用),用于向容器注册的,
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele,BeanDefinition containingBean)
这个方法解析bean节点的name属性,解析别名,接下来还要得到一个BeanDefinition的实例:
396L:AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
这个方法开始解析bean节点的class属性,parent属性
parseMetaElements(ele, bd);——解析元数据
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());——解析lookup
parseConstructorArgElements(ele, bd);——解析构造器
parsePropertyElements(ele, bd);——解析property
各种解析完成,层层返回,注册到容易中,默认情况下,调用容器第一次getBean,就会根据name找到BeanDefinition,就能找到class信息,找到其依赖的property,就可以进行实例化了,假如是单例的话就会缓存起来,下次getBean直接从缓存中获取该实例。