• spring-BeanDefinition流程源码分析


    找入口

    AbstractRefreshableApplicationContext类的refreshBeanFactory方法中第13行代码:

    protected final void refreshBeanFactory() throws BeansException {
            // 如果之前有IoC容器,则销毁
            if (hasBeanFactory()) {
                destroyBeans();
                closeBeanFactory();
            }
            try {
                // 创建IoC容器,也就是DefaultListableBeanFactory
                DefaultListableBeanFactory beanFactory = createBeanFactory();
                beanFactory.setSerializationId(getId());
                customizeBeanFactory(beanFactory);
                // 加载BeanDefinition对象,并注册到IoC容器中(重点)
                loadBeanDefinitions(beanFactory);
                synchronized (this.beanFactoryMonitor) {
                    this.beanFactory = beanFactory;
                }
            }
            catch (IOException ex) {
                throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
            }
        }

    流程解析

    • 进入AbstractXmlApplicationContext的loadBeanDefinitions方法:
      • 创建一个XmlBeanDefinitionReader,通过阅读XML文件,真正完成BeanDefinition的加载和注册。
      • 配置XmlBeanDefinitionReader并进行初始化。
      • 委托给XmlBeanDefinitionReader去加载BeanDefinition。
     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 
                                                    throws BeansException, IOException {
            // Create a new XmlBeanDefinitionReader for the given BeanFactory.
            // 创建一个BeanDefinition阅读器,通过阅读XML文件,真正完成BeanDefinition的加载和注册
            XmlBeanDefinitionReader beanDefinitionReader = new 
                                                XmlBeanDefinitionReader(beanFactory);
    
            // Configure the bean definition reader with this context's
            // resource loading environment.
            beanDefinitionReader.setEnvironment(this.getEnvironment());
            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);
            // 委托给BeanDefinition阅读器去加载BeanDefinition
            loadBeanDefinitions(beanDefinitionReader);
        }
    
        protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws 
                                                        BeansException, IOException {
            // 获取资源的定位
            // 这里getConfigResources是一个空实现,真正实现是调用子类的获取资源定位的方法
            // 比如:ClassPathXmlApplicationContext中进行了实现
            //      而FileSystemXmlApplicationContext没有使用该方法
            Resource[] configResources = getConfigResources();
            if (configResources != null) {
                // XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
                reader.loadBeanDefinitions(configResources);
            }
            // 如果子类中获取的资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
            String[] configLocations = getConfigLocations();
            if (configLocations != null) {
                // XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
                reader.loadBeanDefinitions(configLocations);
            }
        }
    • loadBeanDefinitions方法经过一路的兜兜转转,最终来到了XmlBeanDefinitionReaderdoLoadBeanDefinitions方法:
      • 一个是对XML文件进行DOM解析;
      • 一个是完成BeanDefinition对象的加载与注册
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {
            try {
                // 通过DOM4J加载解析XML文件,最终形成Document对象
                Document doc = doLoadDocument(inputSource, resource);
                // 通过对Document对象的操作,完成BeanDefinition的加载和注册工作
                return registerBeanDefinitions(doc, resource);
            }
            //省略一些catch语句
            catch (Throwable ex) {
                ......
            }
        }
    • 此处我们暂不处理DOM4J加载解析XML的流程,我们重点分析BeanDefinition的加载注册流程
    • 进入XmlBeanDefinitionReaderregisterBeanDefinitions方法:
      • 创建DefaultBeanDefinitionDocumentReader用来解析Document对象。
      • 获得容器中已注册的BeanDefinition数量
      • 委托给DefaultBeanDefinitionDocumentReader来完成BeanDefinition的加载、注册工作。
      • 统计新注册的BeanDefinition数量
    public int registerBeanDefinitions(Document doc, Resource resource) throws 
                                            BeanDefinitionStoreException {
            // 创建DefaultBeanDefinitionDocumentReader用来解析Document对象
            BeanDefinitionDocumentReader documentReader = 
                                        createBeanDefinitionDocumentReader();
            // 获得容器中注册的Bean数量
            int countBefore = getRegistry().getBeanDefinitionCount();
            //解析过程入口,BeanDefinitionDocumentReader只是个接口
            //具体的实现过程在DefaultBeanDefinitionDocumentReader完成
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            // 统计注册的Bean数量
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }
    • 进入DefaultBeanDefinitionDocumentReaderregisterBeanDefinitions方法:
      • 获得Document的根元素标签
      • 真正实现BeanDefinition解析和注册工作
     public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext
        {
            this.readerContext = readerContext;
            logger.debug("Loading bean definitions");
            // 获得Document的根元素<beans>标签
            Element root = doc.getDocumentElement();
            // 真正实现BeanDefinition解析和注册工作
            doRegisterBeanDefinitions(root);
        }
    • 进入DefaultBeanDefinitionDocumentReaderdoRegisterBeanDefinitions方法:
      • 这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
      • 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
      • 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
      • 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
     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.
            
            // 这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
            BeanDefinitionParserDelegate parent = this.delegate;
            this.delegate = createDelegate(getReaderContext(), root, parent);
    
            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)) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                    "] not matching: " + getReaderContext().getResource());
                        }
                        return;
                    }
                }
            }
            // 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
            preProcessXml(root);
            // 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
            parseBeanDefinitions(root, this.delegate);
            // 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
            postProcessXml(root);
    
            this.delegate = parent;
        }
  • 相关阅读:
    列表基本操作——1
    条件判断与嵌套
    数据拼接与数据转换
    变量与赋值
    打印数与type()函数
    print()函数与打印字符串
    arduino开发ESP8266学习笔记二----按键控制LED灯
    arduino开发ESP8266学习笔记一 ----点亮一个LED灯
    无线充电
    EMC设计总结
  • 原文地址:https://www.cnblogs.com/yintingting/p/7896377.html
Copyright © 2020-2023  润新知