Spring源码阅读——bean提取注册过程

代码准备

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源码深度解析》

猜你喜欢

转载自blog.csdn.net/qq_18860653/article/details/80940173