spring源码之XmlBeanDefinitionReader与bean的注册

终于开始spring的源码了,记得距离自己本科阶段ssh的经历,应该已经过去了几年了了。。。

好了闲话不多说,先来看个简单的spring的例子,直接用的是spring的XmlBeanFactory,来看代码:

package fjs;

import java.io.File;
import java.util.Map;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class Say {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public void saying() {
		System.out.println("say is : " + name);
	}
	public void before() {
		System.out.println("before");
	}
	
	public static void main(String args[]) {
		Resource res = new ClassPathResource(
                "beans.xml");
		BeanFactory bf = new XmlBeanFactory(res);
		//ApplicationContext context = new FileSystemXmlApplicationContext("beans.xml");
		//Say say1 = (Say)bf.getBean("say1");
		//Say say2 = (Say)bf.getBean("say1");
		//System.out.println(say1 == say2);
		//say1.saying();
	}
}

这个是主代码,用于从spring的ioc池子中获取bean,那么来看看xml文件的定义:



    
    
	
		
	
	
	
	
	
	
	
	
	
	
		
			
			
			
		
		
		
	

上面还有一部分aop的配置,这里就忽略掉。。。

来看看bean是怎么从xml文件中获取配置信息的吧:

private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

	public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}

	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}

其实在这里就可以看到,基本上都是reader在做事情,这也是这篇文章要做的主要的事情,来分析一些这个XmlBeanDfinitionReader到底是怎么读取数据的,还是先来看看它的继承体系吧:

spring源码之XmlBeanDefinitionReader与bean的注册_第1张图片


这里XmlBeanDefinitionReader的继承体系还是很简单的,相对于spring其他类型的继承来说,那么我们先来看看最顶层的接口都定义了一些什么方法吧:

public interface BeanDefinitionReader {
	//返回用于注册bean的factory
	BeanDefinitionRegistry getRegistry();

	//返回用于加载resource的loader
	ResourceLoader getResourceLoader();


	//获取class loader
	ClassLoader getBeanClassLoader();

	/**
	 * Return the BeanNameGenerator to use for anonymous beans
	 * (without explicit bean name specified).
	 */
	//名字生成器,为那些没有名字的bean生成名字
	BeanNameGenerator getBeanNameGenerator();



	//从resource中获取bean的定义
	int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;


	//从多个resource中获取bean的定义
	int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;


	//给定resource的位置,获取definition
	int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;


	//从多个地址获取definition
	int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}

这里最重要的方法就是loadDefinitions,用于从resource中读取bean的定义,

好了,那么看完了接口的定义,接下来来看看这个loadBeanDefinitions是怎么实现的吧:

	//用于从resource中读取bean的definition
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		//将其组装生encoderesource,这个没啥太大的意思
		return loadBeanDefinitions(new EncodedResource(resource));
	}

好了,这部分代码啥意思都没有,接下来继续吧:

	//加载bean的definition
	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());
		}

		//获取当前的线程变量,它是用于保存处理的resource的
		//这里为什么要用线程变量来保存,不同的线程难道还要保存不同的resource了。。?
		Set currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);  //保存当前的resource
		}
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
			//获取resource的inputStream
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				//xml的input
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				//读取definition
				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();
			}
		}
	}

这部分代码其实也没啥太大的意思,无非就是将resource保存起来,然后获取inputstream,然后在调用别的方法继续处理,不过这里有个自己比较郁闷的地方,为什么要用线程变量来保存处理的resource,难道不同的线程要保存不同的resource了。。?搞不懂。。。以后再说吧,接下来继续看代码:

	//读取xml文件中的beandefinition
	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			int validationMode = getValidationModeForResource(resource);
			Document doc = this.documentLoader.loadDocument(  //获取xml的document
					inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
			return registerBeanDefinitions(doc, resource);   //读取并注册bean的信息
		}
		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);
		}
	}

从这部分代码开始就涉及到xml文件的内部了,说明准备开始解析xml文件了。。。不过内容并不多,可能最主要的就是要处理一些xml解析时候的异常吧,继续看代码:

	//读取bean,并且还要注册
	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		//获取用于读取document的reader  其实是:DefaultBeanDefinitionDocumentReader
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		//将环境穿进去
		documentReader.setEnvironment(this.getEnvironment());
		int countBefore = getRegistry().getBeanDefinitionCount();  //之前已经注册的bean的数目
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //读取definition并注册
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

这里开始准备读取xml文件,新建了一个document的reader,这个reader的类型其实是DefaultBeanDefinitionDocumentReader,然后真正的事情是这个reader来做的。。。那么接下来来看看这个reader做了啥吧:

	//这里要读取并注册bean
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
		Element root = doc.getDocumentElement();  //获取xml的root
		doRegisterBeanDefinitions(root);
	}

这代码没啥意思,我勒个去,接下来继续看吧:

	protected void doRegisterBeanDefinitions(Element root) {
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
		if (StringUtils.hasText(profileSpec)) {
			Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			if (!this.environment.acceptsProfiles(specifiedProfiles)) {
				return;
			}
		}

		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createHelper(this.readerContext, root, parent);

		preProcessXml(root);  //前置处理,不过是空方法
		parseBeanDefinitions(root, this.delegate);   //解析xml文件,并将其注册到beanfactory
		postProcessXml(root);  //后置处理

		this.delegate = parent;
	}

这段代码之后就要开始进行真正的xml文件的解析,并要注册bean的信息了,

	//用于解析当前root下面的node
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			//遍历当前的node
			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)) {
						//解析node的数据,例如bean的id,class路径,property等
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

这部分代码主要在做的事情就是遍历当前xml文件下的node,然后在解析这些node的数据,将其转化为bean的信息保存起来并注册信息:

	//根据不同的node类型,做不同的处理
	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			//这个是处理bea类型的node,也就是bean的定义
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

这里我们就只看看如何处理bean的定义吧,其他的就不看了:

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		//用于将xml定义的bean的基本信息转化为spring定义的数据类型保存起来
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				//相当于是注册bean的definition
				//这里封装了说白了就是bean的id,class路径,scope,property等一些基本的信息,
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			//发送有bean注册的事件
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

那么到这里为止,这个bean的信息的读取就已经差不多了,将bean的数据转化为定义的类型保存起来,具体是什么样子的就不管他了,无非就是一些id,property什么的。。。

那么接下来来看看这个注册的过程是怎么样子的吧:

	//在beanfactory上面注册bean
	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Register bean definition under primary name.
		String beanName = definitionHolder.getBeanName();  //获取bean的名字
		//注册bean,name与definition对应起来,其实是将他们保存在了一个并发map里面
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.  注册别名,呵呵
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String aliase : aliases) {
				registry.registerAlias(beanName, aliase);
			}
		}
	}

这部分的代码就是用于将bean的名字(id)与bean的定义信息关联起来,然后保存在beanFactory的一个map里面,具体来看一下:

	//用于注册bean的信息,将他们保存起来,key是id,value是definition
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}
//加锁
		synchronized (this.beanDefinitionMap) {
			//相当于是判断一下是否有重复的bean
			Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
			if (oldBeanDefinition != null) {
				if (!this.allowBeanDefinitionOverriding) {
					throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
							"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
							"': There is already [" + oldBeanDefinition + "] bound.");
				}
				else {
					if (this.logger.isInfoEnabled()) {
						this.logger.info("Overriding bean definition for bean '" + beanName +
								"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
					}
				}
			}
			else {
				this.beanDefinitionNames.add(beanName);  //将bean的名字保存起来
				this.frozenBeanDefinitionNames = null;
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);  //将数据保存在map里面,这里用的是ConcurrentHashMap
		}

		resetBeanDefinition(beanName);
	}

上述的代码就是整个bean的注册的过程,说白了就是将这些数据保存到当前beanfactory的一个ConcurrentHashMap里面去。。


好了,那么到这里整个bean的定义的解析与注册过程就差不多了,下一篇文章来看看整个生成bean吧。。。

你可能感兴趣的:(java,EE相关)