spring加载bean定义

/ Spring / 没有评论 / 22浏览

spring加载bean定义

分析入口->loadBeanDefinitions

该逻辑的入口为:XmlBeanDefinitionReader.loadBeanDefinitions

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

		//resourcesCurrentlyBeingLoaded记录已经被加载过的资源
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<>(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);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				//加载beandefenition的真正处理逻辑
				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();
			}
		}
	}

该方法一共做了这么3件事: 1、判断该资源是否已经加载解析过,如果有,则抛出异常 2、将编码处理过的Resource资源对象,转成SAX可以解析的InputSource对象 3、将注册的真正处理过程交给doLoadBeanDefinitions处理

验证加载xml并进行解析注册->doLoadBeanDefinitions

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
		throws BeanDefinitionStoreException {
		//....
		//进行xml的验证并且加载
		Document doc = doLoadDocument(inputSource, resource);
		//进行xml文档对象的解析以及对BeanDefinition的注册
		return registerBeanDefinitions(doc, resource);
		//...
}

这个方法做了2件事: 1、进行xml的验证并且加载 2、将内存的xml文档对象解析并进行注册

registerBeanDefinitions

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	//使用DefaultBeanDefinitionDocumentReader进行解析
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	//记录解析前BeanDefinition的个数
	int countBefore = getRegistry().getBeanDefinitionCount();
	//解析注册
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	//返回解析之后的Beandefenition个数
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

进入到DefaultBeanDefinitionDocumentReader.registerBeanDefinitions

	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
		//获取根节点对象
		Element root = doc.getDocumentElement();
		//解析注册
		doRegisterBeanDefinitions(root);
	}

前面都是xml的验证以及加载过程,到这里,xml已经转化为对应的Document对象了,开始进入解析注册阶段。

解析注册->doRegisterBeanDefinitions

protected void doRegisterBeanDefinitions(Element root) {
	//....
	parseBeanDefinitions(root, this.delegate);
	//....
}

节点元素解析->parseBeanDefinitions:

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

默认标签解析->parseDefaultElement

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

以上提供了4种标签(import、alias、bean、beans)的解析方法,重点分析bean标签

解析bean标签:

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		//主要是对bean标签的属性以及子节点进行解析
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				//注册BeanDefenition
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

1、针对以下属性及子节点进行解析(部分省略) 默认属性: 1539004166366.png

1539004187590.png

默认节点 1539004251385.png

2、将解析完成的BeanDefinition注册到map中,见DefaultListableBeanFactory.registerBeanDefinition

    /** Map of bean definition objects, keyed by bean name */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	/** List of bean definition names, in registration order */
	private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
	
   /** List of names of manually registered singletons, in registration order */
	private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

    this.beanDefinitionMap.put(beanName, beanDefinition);
    this.beanDefinitionNames.add(beanName);
    this.manualSingletonNames.remove(beanName);

如图为解析注册完成之后的BeanDefinition: 1539005228089.png

至此,bean标签的解析注册结束,在这个过程中,没有细致分析bean标签解析的相关细节,只是大概知道它有哪些属性以及子节点,更多细节问题还需在使用过程中了解,并再结合源码深入分析。