【Spring源码阅读】BeanDefinition原理与加载流程

版权声明:转载请注明本文源地址 https://blog.csdn.net/qwe6112071/article/details/85222598

BeanDefinition接口定义及其相关子类实现

在Spring容器初始化过程中,Spring会将配置文件中配置的Java类封装成一个个BeanDefinition。
BeanDefinition存储了具体代表Bean的类,并通过实现了AttributeAccessor接口定义了读写属性配置的相关方法。在基于xml配置Spring容器中,我们为某个Bean配置了具体的属性值,这些都根据name-value对映射到BeanDefinition的元数据集合attributes中,在实例化成具体Bean的时候通过AttributeAccessor接口实现的方法完成属性注入。
在这个基础上BeanDefinition定义一个Bean基于Spring容器中的相关属性能力,比如是否为单例,是否支持懒加载,是否支持自动装配、为自动装配首选等。
BeanDefinition作为接口定义,有众多的实现类,常用的如下图所示:
image

  1. AbstractBeanDefinition:BeanDefinition的较为完整、具体的抽象实现类,定义了三大子类ChildBeanDefinition,RootBeanDefinition,GenericBeanDefinition的基础公用实现,具体实现了BeanDefinition属性付覆写,解析获取BeanDefinition对应的BeanClass和Spring相关属性能力的读写等(比如是否为单例,支持自动装配等)
  2. RootBeanDefinition/ChildBeanDefinition:BeanDefinition存在父子关系,子BeanDefinition用ChildBeanDefinition表示,父BeanDefinition或没有父子关系的用RootBeanDefinition表示。
  3. GenericBeanDefinition: 相比于RootBeanDefinition和ChildBeanDefinition在定义的时候就必须硬编码,GenericBeanDefinition的优点可以动态的为GenericBeanDefinition设置parent。
  4. AnnotatedBeanDefinition:读取基于注解定义的Bean。

Spring解析加载BeanDefinition流程

最终加载资源前的复杂过程

在最终开始加载资源,会经过一系列繁琐的准备工作,核心加载逻辑在下一节doLoadBeanDefinitions加载逻辑实现描述,下面先是前期的准备工作:
在Spring初始化容器过程,第一步首先创建BeanFactory的时候,会调用AbstractApplicationContext的obtainFreshBeanFactory方法,里面会调用AbstractApplicationContext类中实现的refreshBeanFactory方法,在这个方法里,调用了loadBeanDefinitions(beanFactory)来解析BeanDefinition,具体如下所示

protected final void refreshBeanFactory() throws BeansException {
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		beanFactory.setSerializationId(getId());
		customizeBeanFactory(beanFactory);
		// 加载Beanfinitions
		loadBeanDefinitions(beanFactory);
		synchronized (this.beanFactoryMonitor) {
			this.beanFactory = beanFactory;
		}
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}

具体实现如下:

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// 先创建一个基于xml的BeanDefinitionReader。
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

	// 设置上下文环境和资源加载器,环境主要根据profile进行配置
	beanDefinitionReader.setEnvironment(this.getEnvironment());
	beanDefinitionReader.setResourceLoader(this);
	//设置xml解析工具
	beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

	// 在初始化里调用了reader.setValidating(this.validating),其中this.validating默认为true,表示需要验证xml文件格式
	initBeanDefinitionReader(beanDefinitionReader);
	// 尝试获取配置文件位置后,调用XmlBeanDefinitionReader内方法进行加载
	loadBeanDefinitions(beanDefinitionReader);
}

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

XmlBeanDefinitionReader的loadBeanDefinitions方法定义在抽象父类AbstractBeanDefinitionReader中:

public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader {
    // 先调用这个方法    
	public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int counter = 0;
		//根据传入的位置数组遍历加载,对加载的BeanDefinition个数进行累加返回
		for (String location : locations) {
			counter += loadBeanDefinitions(location);
		}
		return counter;
	}
	// 随后调用这个方法
	public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(location, null);
	}
	
	//最后调用这个方法
	public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
		}

		if (resourceLoader instanceof ResourcePatternResolver) {
			// 根据根据模式配置加载路径资源
			try {
			    // 解析资源通配拿到资源数组
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				// 内部是一个for循环遍历,最终调用int loadBeanDefinitions(Resource resource)方法
				int loadCount = loadBeanDefinitions(resources);
				if (actualResources != null) {
					for (Resource resource : resources) {
						actualResources.add(resource);
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
				}
				return loadCount;
			}
			catch (IOException ex) {
				throw new BeanDefinitionStoreException(
						"Could not resolve bean definition resource pattern [" + location + "]", ex);
			}
		}
		else {
			// 只能根据绝对路径加载单个
			Resource resource = resourceLoader.getResource(location);
				// 具体加载操作,调用int loadBeanDefinitions(Resource resource)
			int loadCount = loadBeanDefinitions(resource);
			if (actualResources != null) {
				actualResources.add(resource);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
			}
			return loadCount;
		}
	}
	// 
	public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
		Assert.notNull(resources, "Resource array must not be null");
		int counter = 0;
		for (Resource resource : resources) {
			counter += loadBeanDefinitions(resource);
		}
		return counter;
	}
	
	// 最终调用方法入口,对资源进行编码
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}
	// 传入编码后的资源,调用下面函数
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isInfoEnabled()) {
			logger.info("Loading XML bean definitions from " + encodedResource.getResource());
		}

        // 初始加载为null,初始化一个HashSet,存入资源入参
		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();
			try {
				InputSource inputSource = new InputSource(inputStream);
				// 首次加载为null
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				// 最终实际加载资源操作
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}
}

doLoadBeanDefinitions校验、解析xml文件流程

通过上面一系列的资源路径检索和检查,最终进入了下面开始真正的加载资源的逻辑

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
		throws BeanDefinitionStoreException {
	try {
	    // 有3种验证方式,VALIDATION_AUTO、VALIDATION_DTD、VALIDATION_XSD,如果为第一种,会根据xml文件的头部是DTD类型还是XSD类型格式文件解析
		int validationMode = getValidationModeForResource(resource);
		/*
		    java加载xml文档的基本流程,封装了以下步骤:
		    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		    DocumentBuilder builder = factory.newDocumentBuilder();
		    builder.setEntityResolver(entityResolver);
		    builder.parse(inputSource)
		*/
		Document doc = this.documentLoader.loadDocument(
				inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
		// 走到这一步,说明xml文件的格式校验,Java解析工作已完成,下面进一步解析xml文件的具体内容,创建BeanDefinition。
		return registerBeanDefinitions(doc, resource);
	}
	catch (BeanDefinitionStoreException ex) {
		throw ex;
	}
	catch (SAXParseException ex) {
		throw new XmlBeanDefinitionStoreException(resource.getDescription(),
				"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
	}
	catch (SAXException ex) {
		throw new XmlBeanDefinitionStoreException(resource.getDescription(),
				"XML document from " + resource + " is invalid", ex);
	}
	catch (ParserConfigurationException ex) {
		throw new BeanDefinitionStoreException(resource.getDescription(),
				"Parser configuration exception parsing XML from " + resource, ex);
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException(resource.getDescription(),
				"IOException parsing XML document from " + resource, ex);
	}
	catch (Throwable ex) {
		throw new BeanDefinitionStoreException(resource.getDescription(),
				"Unexpected exception parsing XML document from " + resource, ex);
	}
}

registerBeanDefinitions 解析文档创建BeanDefinition

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    // 创建文档读取器DefaultBeanDefinitionDocumentReader进行解析文档
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	documentReader.setEnvironment(getEnvironment());
	// 获取当前已经存在的BeanDefinition数量,便于后面解析完后再一次获取数量,两次相减得到这次解析的数量
	int countBefore = getRegistry().getBeanDefinitionCount();
	// 具体注册操作
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	// 获取这次解析的BeanDefinition数量
	return getRegistry().getBeanDefinitionCount() - countBefore;
}
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    	this.readerContext = readerContext;
    	logger.debug("Loading bean definitions");
    	// 获取文档根节点
    	Element root = doc.getDocumentElement();
    	// 真正注册流程
    	doRegisterBeanDefinitions(root);
    }
    
    protected void doRegisterBeanDefinitions(Element root) {
        // 判断xml配置文件中是否指定了环境
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
		if (StringUtils.hasText(profileSpec)) {
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			if (!getEnvironment().acceptsProfiles(specifiedProfiles)) {
				return;
			}
		}

		// 创建委托解析对象,在解析xml过程中,默认为Beans命名空间
		// 但实际可能会有多个命名空间
		// 如<aop:cofnig>等,或嵌套的如<bean class = "xxx" p:arg1="xxx">
		// 对于非默认命名空间的,会委托给BeanDefinitionParserDelegate进行解析。
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(this.readerContext, root, parent);

        // 解析前处理,留给子类拓展
		preProcessXml(root);
		// 具体解析操作
		parseBeanDefinitions(root, this.delegate);
		// 解析后处理,留给子类拓展
		postProcessXml(root);

		this.delegate = parent;
	}
    
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        // 如果根节点是默认命名空间,直接走Beans命名空间处理
		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 {
		    // 交给委托对象处理自定义的命名空间如aop,p等或用户自定义的命名空间
			delegate.parseCustomElement(root);
		}
	}
	// 默认的解析流程如下,如果节点是import,alias,beans,bead等类型,则调用相关的方法依次进行解析配置里的属性
	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
	    // import标签
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		// alias标签
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		// bean标签,核心解析逻辑
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		// 嵌套beans标签
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}
	
	// 对于自定义的命名空间,会走以下流程,先根据元素获取命名空间地址,再根据地址找到相应的配置文件找到对应的映射处理器,再交由相关的处理器进行解析
	// 如<aop:xxx>则交给AopNamespaceHandler,<context:xxx>则交给ContextNamespaceHandler等。
	public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
		String namespaceUri = getNamespaceURI(ele);
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}
}

至此,xml配置文件解析成相应的BeanDefinition流程如上所示,对于具体的将xml标签里的一个个诸如class,id等元素解析为具体的BeanDefinition属性,中间流程过于繁杂,但原理相对还是比较清晰的,这里就不细述了。

猜你喜欢

转载自blog.csdn.net/qwe6112071/article/details/85222598