ZFYCH_Love

Simply but Powerful

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  115 随笔 :: 1 文章 :: 36 评论 :: 18万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

 

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.创建beanFactory
2.根据web.xml中contextConfigLocation配置的路径,读取Spring配置文件,封装为Resource
3.根据Resource加载XML配置文件(bean文件)并解析为Document对象
4.遍历Document,解析为beanDefinition。

 

posted on   xiaoyang_  阅读(189)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
历史上的今天:
2016-04-22 Hadoop学习10--常用命令记录帖
2016-04-22 Hadoop学习9--动态增加datanode
2014-04-22 【wp之二 页面布局】
2013-04-22 发现一个系列学习wcf的好文章,通读了一遍,地址记下来
点击右上角即可分享
微信分享提示