程序笔记   发布时间:2022-07-21  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了【学习底层原理系列】重读spring源码3-加载beanDefinition的方法obtainFreshBeanFactory大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

 

obtainFreshBeanFactory()方法概述

定义BeanFactory,并加载以下两种bean的定义,装配到BeanFactory:

1.配置文件中定义的bean

2.通过<context:component-scan base-package="..." />配置的路径下的,且经过相应注解标注的所有类,注解包括:@Controller、@service、@Component、@Repository

源码解读

主要流程总结:

1.创建BeanFactory:DefaultListableBeanFactory

2.解析web.xml配置,读取spring配置文件,封装为resource对象

3.把resource对象封装为Document对象

4.开始层层遍历Document的节点。

以下是细节:

先来看该方法的实现,注:这里会把无关代码删掉,以方便阅读。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //刷新bean工厂
     this.refreshBeanFactory();
    //创建bean工厂
    return this.getBeanFactory();
 } 

重点看刷新bean工厂部分:

protected final void refreshBeanFactory() throws BeansException {
       //创建bean工厂
            DefaultListableBeanFactory beanFactory = createBeanFactory();
        //这里加载beanDefinition,并赋给bean工厂          
       loadBeanDefinitions(beanFactory);
    }
createBeanFactory()好理解,就是new了个工厂对象。有了工厂对象后,就需要往里面装载东西,装什么呢?这里是

接下来看loadBeanDefinitions(beanFactory)方法的具体实现:创建xml文件读取器

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 以下这一堆内容就是为了准备一个xml文件读取器,仅作了解
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
     beanDefinitionReader.setEnvironment(this.getEnvironment());              beanDefinitionReader.setresourceLoader(this);
       beanDefinitionReader.setEntityResolver(new resourceEntityResolver(this));

      initBeanDefinitionReader(beanDefinitionReader);
    //这里才是核心,加载beanDefinition的工作还没开始
        loadBeanDefinitions(beanDefinitionReader);
    }

继续跟进去,这里依然“没干正事”:加载spring配置文件

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        resource[] configresources = getConfigresources();
        if (configresources != null) {
            reader.loadBeanDefinitions(configresources);
        }
        String[] configLOCATIOns = getConfigLOCATIOns();
        if (configLOCATIOns != null) {
          //核心代码
        reader.loadBeanDefinitions(configLOCATIOns);
        }
    }

接着看核心代码

public int loadBeanDefinitions(String LOCATIOn, Set<resource> actualresources) throws BeanDefinitionStoreException {
        resourceLoader resourceLoader = getresourceLoader();
        if (resourceLoader instanceof resourcePatternResolver) {
            // 通配符模式匹配资源,转换为resource对象。spring提供了多种resourceLoader,根据通配符匹配,生成对应类型的resource
                resource[] resources = ((resourcePatternResolver) resourceLoader).getresources(LOCATIOn);          //【继续把加载工作往后放】          int loadCount = loadBeanDefinitions(resources);return loadCount;
            }
        }
        else {
            // 以绝对路径加载单个资源文件,转换为resource对象
            resource resource = resourceLoader.getresource(LOCATIOn);       //【继续把加载工作往后放】
            int loadCount = loadBeanDefinitions(resourcE);return loadCount;
        }
    }

通过上面一步,把配置资源转化为resource对象,然后作为参数传入loadxxx方法里进行解析。

进入下面的实现发现,依然在做准备工作:将resource读取为流

public int loadBeanDefinitions(Encodedresource encodedresourcE) throws BeanDefinitionStoreException {
     //
        Set<Encodedresource> currentresources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentresources == null) {
            currentresources = new HashSet<Encodedresource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentresources);
        }
        if (!currentresources.add(encodedresourcE)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedresource + " - check your import definitions!");
        }
        try {
            InputStream inputStream = encodedresource.getresource().geTinputStream();
                Inputsource inputsource = new Inputsource(inputStream);
                if (encodedresource.getEncoding() != null) {
                    inputsource.setEncoding(encodedresource.getEncoding());
                }
               //终于到do...是不是这里就开始真正的执行加载了?
                return doLoadBeanDefinitions(inputsource, encodedresource.getresource());       
        }
        catch (IOException eX) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedresource.getresource(), eX);
        }
        finally {
            currentresources.remove(encodedresourcE);
            if (currentresources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

来看下,删除非核心代码,就做了两件事,先读取资源对象resource,封装成Document对象;再“注册”beanDefinition。

protected int doLoadBeanDefinitions(Inputsource inputsource, resource resourcE)
            throws BeanDefinitionStoreException {
            //生成Document对象
            Document doc = doLoadDocument(inputsource, resourcE);
        //注册BeanDefinition
            return registerBeanDefinitions(doc, resourcE);
        
    }

中间又经历了n个准备环境,最终进入方法parseBeanDefinitions,拿到了Document对象的根节点,开始调用解析方法解析节点:

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 {
            delegate.parseCustomElement(root);
        }
    }

具体的解析逻辑,可以参以下文章:https://blog.csdn.net/v123411739/article/details/86669952

BeanDefinition包含的主要内容:

@todo

解析完成后,依然是注入到BeanFactory中缓存起来,供后续使用,主要的内容是两部分:

1.beanDefinitionNames

2.beanDefinitionMap

总结:

obtainFreshBeanFactory()方法的主要作用:1.创建beanFactory2.根据web.xml中contextConfigLOCATIOn配置的路径,读取Spring配置文件,封装为resource3.根据resource加载XML配置文件(bean文件)并解析为Document对象4.遍历Document,解析为beanDefinition。

 

大佬总结

以上是大佬教程为你收集整理的【学习底层原理系列】重读spring源码3-加载beanDefinition的方法obtainFreshBeanFactory全部内容,希望文章能够帮你解决【学习底层原理系列】重读spring源码3-加载beanDefinition的方法obtainFreshBeanFactory所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。