上面一篇提到了bean加载的入口:
AbstractRefreshableApplicationContext的refreshBeanFacotry中有一行代码:
loadBeanDefinitions(beanFactory);
当前的applicationcontext的实现类是xmlwebapplicationContext,所以最终的loadbeanDefinitions(beanFactory)
方法的实现是在xmlwebapplicationContext中:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = XBeanHelper.createBeanDefinitionReader(this, beanFactory, xmlPreprocessors); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
很容易就能发现,bean的加载的是通过最后一行实现的。继续追踪进入源码:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) { for (String configLocation : configLocations) { reader.loadBeanDefinitions(configLocation); } } }
现在知道为什么可以在web.xml中配置spring的时候指定多个配置文件了吧?哈哈。
继续追踪XmlBeanDefinitionReader这个类。这个类继承了AbstractBeanDefinitionReader。AbstractBeanDefinitionReader还有一个实现类:PropertiesBeanDefinitionReader。
从名字很容易可以看出spring能支持基于xml和基于properties文件的bean加载方式。XmlBeanDefinitionReader
过把xml加载到一个Document对象里面,然后通过BeanDefinitionDocumentReader来分析这个document对象。
BeanDefinitionDocumentReader的默认实现类是:DefaultBeanDefinitionDocumentReader。
其中注册bean的代码如下:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); preProcessXml(root); parseBeanDefinitions(root, delegate); postProcessXml(root); }
spring在这里提供了xml配置文件解析的两个扩展接口:preProcessXml,postProcessXml. 用户可以根据自身需求
扩展这两个接口。下面就关注一下上面代码里面加载bean的核心方法:parseBeanDefinition.
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(delegate.getNamespaceURI(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; String namespaceUri = delegate.getNamespaceURI(ele); if (delegate.isDefaultNamespace(namespaceUri)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
从上面代码可以看出,xml配置文件里面的<beans></beans>标签里面的闭合标签被解析成一个个Node.然后
调用每个标签的NameSpaceHandler进行标签的解析,并注册相应的bean。比如:解析<aop:config></aop:config>
这种标签时会调用AopNamespaceHandler来进行解析。对于使用默认NameSpace的标签,又分为import,alias,bean三个标签进行解析并注册相应的bean。
至此,bean的注入的轮廓基本清晰了。有兴趣的朋友可以沿着这个思路继续深入一些细节,比如aop的注入等等。