代码准备
public class Demo1XmlBeanFactory {
public static void main(String[] args) {
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring/spring-demo1.xml"));
MyService myService = beanFactory.getBean(MyService.class);
myService.doSomeThing();
}
}
BeanDefinition定义及作用
BeanDefinition作为定义springBean文件中bean的接口,可以说是bean的抽象数据结构,它包括属性参数,构造器参数,以及其他具体的参数。当 BeanDefinition 注册完毕以后, Spring Bean 工厂就可以随时根据需要进行实例化了。对于XmlBeanFactory 来说,实例化默认是延迟进行的,也就是说在 getBean 的时候才会;而对于 ApplicationContext来说,实例化会在容器启动后通过 AbstractApplicationContext 中 reflash 方法自动进行
debug进入源码,查看bean提取注册过程
debug开始后,依次进入
- XmlBeanFactory.class
- this.reader.loadBeanDefinitions(resource);
- doLoadBeanDefinitions(inputSource, encodedResource.getResource());
- registerBeanDefinitions(doc, resource); 在这个方法执行之前,需要获取doc,Document doc = doLoadDocument(inputSource, resource);再深入 this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());这主要是一个解析XML的过程。其中getValidationModeForResource(resource)是获取验证模式 - documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 这里开始进行bean的提取注册,继续深入
doRegisterBeanDefinitions(Element root) 这里开始真正进行解析
//解析每一个定义在XML中的bean protected void doRegisterBeanDefinitions(Element root) { //doSomething...处理解析,一些profile的操作,如环境中配置了,则需要去读取,例如web.xml中配置了spring.profile.dev //解析前处理,留给子类处理(具体不实现,交给继承者实现。模板方法设计模式的应用) preProcessXml(root); //真正解析注册bean parseBeanDefinitions(root, this.delegate); //解析后处理,留给子类处理 postProcessXml(root); this.delegate = parent; }
真正解析注册bean:parseBeanDefinitions(root, this.delegate);
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)) {
//对bean的处理
parseDefaultElement(ele, delegate);
}
else {
//对bean的处理
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
最终,当你继续深入,就可以看到最终的注册registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
有一个地方比较重要,Spring对于解析自己的bean 是因为xml中对bean的声明,但是对于一些自定义的,比如,我们使用dubbo的时候 会使用dubbo自定义的的标签,是通过delegate.isDefaultNamespace来选择哪种解析方式的。自定义标签的解析这里就不深入了,知道是在这里发生的即可。
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)) {
//解析Spring 默认标签
parseDefaultElement(ele, delegate);
}
else {
//解析自定义标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
当然,有人会问注册完成后的bean去了哪里呢?
之前说过,整个容器的核心类是 DefaultListableBeanFactory,在其中保存着我们注册完成的bean,当然,你debug进入后,也会最后进入这里,其定义了一个ConcurrentHashMap
参考文档
《Spring源码深度解析》