以 ClassPathXmlApplicationContext 方式启动容器为例
首先是ClassPathXmlApplicationContext的构造器中的refresh方法
refresh方法中依次调用:ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
然后下面列出类与方法,org.springframework 简写为 o.s 类名与方法名之间用#分隔
o.s.context.support.AbstractApplicationContext#obtainFreshBeanFactory
o.s.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
o.s.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(o.s.beans.factory.support.DefaultListableBeanFactory)
o.s.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(o.s.beans.factory.xml.XmlBeanDefinitionReader)
o.s.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(o.s.core.io.Resource...)
o.s.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(o.s.core.io.Resource)
o.s.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(o.s.core.io.support.EncodedResource)
o.s.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions()
o.s.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions()
然后我们继续看registerBeanDefinitions方法的具体实现代码
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//这里实际是 DefaultBeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
//1
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
继续进入 documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
可以看到调用了doRegisterBeanDefinitions(root); 代码如下
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//如果是默认命令空间处理,但我们本次要看的是非默认命令空间 如 context 因此暂时不看。
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
preProcessXml(root);
//这里是重点 是对元素的解析
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//默认命令空间
if (delegate.isDefaultNamespace(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;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {//非默认命令空间, 如 context等的解析处理 继续追踪这个方法代码
delegate.parseCustomElement(root);
}
}
接下来 就比较简单了,代码也比较简单不再详述。简要的说做了如下的这些事:
1、根据传入的element 找到对应的命令空间字符串
2、扫描classpath下所有的META-INF/spring.handlers文件,形成map
3、使用第1步中的字符串,匹配到NamespaceHandler的具体实现类并实例化
4、调用init方法,注入对应localname 的处理器,parse方法,找到具体的localname的解析器
5、调用对应解析器的parse方法
比如 context:component-scan 对应的处理,我们打开spring-context jar文件,找到spring.handlers文件,就会看到它context命名空间处理器为 org.springframework.context.config.ContextNamespaceHandler
查看其中的init方法,就知道 component-scan 对应的解析器为
org.springframework.context.annotation.ComponentScanBeanDefinitionParser
另:
通过查看ComponentScanBeanDefinitionParser 的源码,我们看到component-scan 默认具有annotation-config的功能(看官方文档也能知道)。它的作用是:
1、扫描指定路径下被component注解标注的类(当然也能扫描到Service Repository Controller 因为这些是它的子类),作为bean,注入到容器中。
2、注入了一些注册配置处理器,对autowired resource等注解标记的属性注入bean(即依赖注入),有如下一些处理器
ConfigurationClassPostProcessor
AutowiredAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor 等
(具体请看方法源码:o.s.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(o.s.beans.factory.support.BeanDefinitionRegistry, java.lang.Object))
最后,我们在ComponentScanBeanDefinitionParser的parse 方法中打一个断点,可以看到整个全貌,便于整体理解。
参考资料: