• 2. Spring 源码之 obtainFreshBeanFactory方法


    1. 概述

    创建容器对象DefaultListableBeanFactory,通过loadBeanDefinitions(beanFactory)初始胡documentReader,并对xml文件(及其它文件)读取及解析,包含默认命名空间的解析,自定义标签的解析(以xml为例子)

    2. 源码分析

    2.1 obtainFreshBeanFactory()

    -> 执行获取新鲜的工厂。

    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    /=====================
      	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    		// 初始化BeanFactory,并进行XML文件读取,解析
        //并将得到的BeanFactory记录在AbstractRefreshableApplicationContext的属性中
    		refreshBeanFactory();
    		// 返回当前实体的beanFactory属性
    		return getBeanFactory();
    	}  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    2.2 refreshBeanFactory()
    AbstractRefreshableApplicationContext.java
    @Override
    	protected final void refreshBeanFactory() throws BeansException {
    // 如果存在beanFactory,则销毁beanFactory
    		if (hasBeanFactory()) {
    			destroyBeans();
    			closeBeanFactory();
    		}
    		try {
    // 创建DefaultListableBeanFactory对象;全是空的属性
    DefaultListableBeanFactory beanFactory = createBeanFactory();
    // 为了序列化指定id,可以从id反序列化到beanFactory对象
                beanFactory.setSerializationId(getId());
    // 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象(bean信息覆盖)以及循环依赖。
     // allowCircularReferences 同名属性在 AbstractRefreshableApplicationContext类中和  DefaultListableBeanFactory都有。 
    //子类复写了,调用子类的  
                customizeBeanFactory(beanFactory);
    // 初始化documentReader,并进行XML文件读取及解析,默认命名空间的解析,自定义标签的解析
    			loadBeanDefinitions(beanFactory);
    this.beanFactory = beanFactory;
    		}
    //.....		
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    2.3 loadBeanDefinitions(beanFactory);
    AbstractXmlApplicationContext.java
    @Override
    	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // 为给定的BeanFactory创建一个xml的beanDefinitionReader.并通过回调设置到beanFactory中
    		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    // 给reader对象设置环境对象
            beanDefinitionReader.setEnvironment(this.getEnvironment());
    		beanDefinitionReader.setResourceLoader(this);
    		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    //  初始化beanDefinitionReader对象,此处设置配置文件是否要进行验证
    		initBeanDefinitionReader(beanDefinitionReader);
    // 开始完成beanDefinition的加载
    		loadBeanDefinitions(beanDefinitionReader);
    	}
    
    //==============================
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    		// 以Resource的方式获得配置文件的资源位置
    		Resource[] configResources = getConfigResources();
    		if (configResources != null) {
    			reader.loadBeanDefinitions(configResources);
    		}
    // 以String的形式获得配置文件的位置
    		String[] configLocations = getConfigLocations();
    		if (configLocations != null) {
    //通过reader 开始向下处理
                reader.loadBeanDefinitions(configLocations);
    		}
    	}
    
    
    • 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
    2.3 loadBeanDefinitions(…)

    AbstracttBeanDefinitionReader.java

    资源经过变化,转化成可处理的Resource对象。

    从String[] -string-Resource[]- resource
    
    • 1
    2.4 doLoadBeanDefinitions

    XmlBeanDefinitionReader.java

    进过上面的转化,到了处理的核心步骤

    protected int  doLoadBeanDefinitions(InputSource inputSource, Resource resource)
        
    // 此处获取xml文件的document对象,
    // 这个解析过程是由documentLoader完成的,最终开始将resource读取成一个document文档,
    Document doc = doLoadDocument(inputSource, resource);
    // 根据文档的节点信息封装成一个个的
    //BeanDefinition对象
    int count = registerBeanDefinitions(doc, resource);
    return count;
    
    
    //==============================
    public int registerBeanDefinitions(Document doc, Resource resource)
    // 对xml的beanDefinition进行解析
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    		int countBefore = getRegistry().getBeanDefinitionCount();
    		// 通过documentReader完成具体的解析过程。将beanDefinition注册进beanFactory中
    		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    		return getRegistry().getBeanDefinitionCount() - countBefore;
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    2.5 registerBeanDefinitions

    DefaultBeanDefinitionDocumentReader

    	@Override
    	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    		this.readerContext = readerContext;
    		doRegisterBeanDefinitions(doc.getDocumentElement());
    	}
    	
    //========================
    //开始真正的去解析
    ==>parseBeanDefinitions(root, this.delegate);
    
    //============================
    //遍历每一个节点的信息,判断使用默认的解析方法,还是自定义的解析方法
    
    if (delegate.isDefaultNamespace(ele)) {		
        //默认,import 、alais、bean、beans 标签使用默认解析器
        parseDefaultElement(ele, delegate);}
    else {
    //根据命名空间获取处理器,在处理器中根据属性标签,获取解析器,解析
    	delegate.parseCustomElement(ele);}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    2.5 parse
    2.5.1 使用默认的解析器,解析bean标签

    解析完成,封装成beanDefination,并将结果存储到DefaultListableBeanFactory中,供以后使用。

    this.beanDefinitionMap.put(beanName, beanDefinition);
    
    this.beanDefinitionNames.add(beanName);
    
    • 1
    • 2
    • 3
    2.5.2 使用自定义的解析器

    本例通过Context 标签。

    	@Nullable
    	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
    		// 获取对应的命名空间
    		String namespaceUri = getNamespaceURI(ele);
    
    		// 根据命名空间找到对应的NamespaceHandler ,且执行了将解析器放入parses 属性中.
    //NamespaceHandlerSupport-> 
    //        	private final Map parsers = new HashMap<>();
    //供以后通过名称查找对应的解析器
            
    		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    	//举例使用ContextNamespaceHandler ,里面包含很多解析器
    		// 调用自定义的NamespaceHandler进行解析。通过findParserForElement,找到对应的解析器
    		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3. 思考

    1. 加载->注册->解析,依次递进的过程
  • 相关阅读:
    强化深度学习中利用时序差分法中的Sarsa算法解决风险投资问题实战(附源码 超详细必看)
    Git及Github初学者教程
    由浅入深Dubbo网络通信深入解析
    嵌入式系统中的GPIO控制与应用
    大话Stable-Diffusion-Webui-客制化主题(一)
    sqlmap语法介绍
    【PHP】PHP7中的引用计数
    C++ Reference: Standard C++ Library reference: C Library: cwctype: wctype
    UDP报文结构
    python基于django的校园公寓宿舍报修管理系统设计与实现
  • 原文地址:https://blog.csdn.net/sbl19940819/article/details/127962771