二. 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();
	}  
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;
		}
//.....		
	}
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);
		}
	}

2.3 loadBeanDefinitions(…)

AbstracttBeanDefinitionReader.java

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

从String[] -string-Resource[]- resource
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;
	}

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);}

2.5 parse
2.5.1 使用默认的解析器,解析bean标签

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

this.beanDefinitionMap.put(beanName, beanDefinition);

this.beanDefinitionNames.add(beanName);
2.5.2 使用自定义的解析器

本例通过Context 标签。

	@Nullable
	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		// 获取对应的命名空间
		String namespaceUri = getNamespaceURI(ele);

		// 根据命名空间找到对应的NamespaceHandler ,且执行了将解析器放入parses 属性中.
//NamespaceHandlerSupport-> 
//        	private final Map<String,  BeanDefinitionParser> parsers = new HashMap<>();
//供以后通过名称查找对应的解析器
        
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
	//举例使用ContextNamespaceHandler ,里面包含很多解析器
		// 调用自定义的NamespaceHandler进行解析。通过findParserForElement,找到对应的解析器
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

3. 思考

  1. 加载->注册->解析,依次递进的过程
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值