`
zddava
  • 浏览: 240433 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring源代码分析 -- IOC容器(一)

阅读更多
Spring是知道很久了,一直断断续续在看,不过用到它的机会不是很多,于是想阅读一下Spring的源代码来更深入的了解下这个框架(源代码的版本是2.5.6)。首先,当然是从Spring的IOC容器开始了,最基本的IOC容器就是org.springframework.beans.factory.BeanFactory了,这个接口定义了一个基本的IOC容器应该具有的行为,其源代码如下所示:

public interface BeanFactory {

	/** 通过在bean的名字前加上&可以返回生成Bean的FactoryBean本身 */
	String FACTORY_BEAN_PREFIX = "&";

	/** 根据名字返回Bean */
	Object getBean(String name) throws BeansException;

	/** 根据名字和类型返回Bean */
	Object getBean(String name, Class requiredType) throws BeansException;

	/** 用于使用静态方法工厂创建prototype的bean,args是给工厂方法的参数 */
	Object getBean(String name, Object[] args) throws BeansException;

	/** 查询IOC容器中是否有特定名字的Bean */
	boolean containsBean(String name);

	/** 判断Bean是不是单例的 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/** 判断Bean是不是原型的 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/** 判断名字为name的Bean的类型是否是targetType */
	boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;

	/** 返回Bean的类型 */
	Class getType(String name) throws NoSuchBeanDefinitionException;

	/** 判断Bean的所有别名,如果使用别名查询的,那么Bean的原始名字也会返回的 */
	String[] getAliases(String name);

}


BeanFactory是一切IOC容器类的基接口,它定义了IOC容器的基本行为,下面来看几个具体的实现类,首先从XmlBeanFactory开始。

public class XmlBeanFactory extends DefaultListableBeanFactory {

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

}


这个类的构造函数说明了配置文件的载入过程,就是通过XmlBeanDefinitionReader的#loadBeanDefinitions()方法来载入的,源代码如下:

	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}


它又进一步调用了#loadBeanDefinitions(EncodedResource)这个方法,它的源代码如下。

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

		Set currentResources = (Set) this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		// 如果Set中已经包含了这个资源,那么就不要重复载入
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException("Detected recursive loading of "
					+ encodedResource + " - check your import definitions!");
		}
		try {
			// 构建一个解析XML使用的InputStream对象
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				// 实做Bean定义的载入
				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.set(null);
			}
		}
	}


这样,经过了一些列的处理,最后来到了实做载入的#doLoadBeanDefinitions()方法。

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			int validationMode = getValidationModeForResource(resource);

			// 通过InputSource来载入XML到一个Document对象
			Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(),
					this.errorHandler, validationMode, isNamespaceAware());
			// 注册Bean的定义
			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);
		}
	}


下面首先来看一下这个Document的获取过程,这里documentLoader是一个org.springframework.beans.factory.xml.DefaultDocumentLoader类的对象,通过它的#loadDocument()方法可以获得一个Document对象,这个过程先不去仔细看,主要来看一下这个#registerBeanDefinitions()方法。

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// 支持老的XmlBeanDefinitionParser
		if (this.parserClass != null) {
			XmlBeanDefinitionParser parser = (XmlBeanDefinitionParser) BeanUtils
					.instantiateClass(this.parserClass);
			return parser.registerBeanDefinitions(this, doc, resource);
		}
		// 使用BeanDefinitionDocumentReader来载入
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// 已经注册的Bean数量
		int countBefore = getRegistry().getBeanDefinitionCount();
		// 注册Bean
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}


这里XmlBeanDefinitionParser的处理就不仔细看了,因为是Spring为了兼容老的实现而保留的,下边主要来看一下使用BeanDefinitionDocumentReader的处理过程。

首先就应该是BeanDefinitionDocumentReader的构造,就是#createBeanDefinitionDocumentReader()方法

	protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
		return (BeanDefinitionDocumentReader) BeanUtils.instantiateClass(this.documentReaderClass);
	}


这里的documentReaderClass这个变量的值为DefaultBeanDefinitionDocumentReader.class,也就是org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader,也就是BeanDefinitionDocumentReader的实现类。

下面来看看它的#registerBeanDefinitions()方法。

	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;

		logger.debug("Loading bean definitions");
		// 根元素
		Element root = doc.getDocumentElement();
		
		// 这个类很重要,主要是委托给它来实现解析
		BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);

		// 如果想自己实现Bean的注册过程,可以继承DefaultBeanDefinitionDocumentReader,
		// 然后覆盖#preProcessXml()和#postProcessXml()来完成更多的个性化实现。
		
		// 处理XML前,默认无行为
		preProcessXml(root);
		
		// 解析Bean的定义
		parseBeanDefinitions(root, delegate);
		
		// 处理XML后,默认无行为
		postProcessXml(root);
	}


这个方法有两个部分需要考虑下,一个是BeanDefinitionParserDelegate实例的构建,另外一个是#parseBeanDefinitions()方法。

首先来看一下BeanDefinitionParserDelegate的构建

	protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) {
		BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
		delegate.initDefaults(root);
		return delegate;
	}


这里调用了BeanDefinitionParserDelegate的#initDefaults()方法来初始化,并把document的root元素作为参数传递了进去。这个方法主要是对一些全局属性的初始化,可以看看它的源代码:

	public void initDefaults(Element root) {
		DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();
		// default-lazy-init -> 默认的延迟加载
		defaults.setLazyInit(root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE));
		// default-merge -> 对集合类的默认merge处理
		defaults.setMerge(root.getAttribute(DEFAULT_MERGE_ATTRIBUTE));
		// default-autowire -> 默认的自动装配
		defaults.setAutowire(root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE));
		// default-dependency-check -> 默认的依赖检测
		defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
		// default-autowire-candidates -> 查找自动装配的Bean的样式
		if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
			defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
		}
		// default-init-method -> 默认初始化方法
		if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
			defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
		}
		// default-destroy-method -> 模式销毁方法
		if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
			defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
		}
		defaults.setSource(this.readerContext.extractSource(root));

		this.defaults = defaults;
		this.readerContext.fireDefaultsRegistered(defaults);
	}


这个方法提供了针对根标签<beans>的属性(xml定义的bean的一些默认行为)的载入。在这里会看到很多spring配置文件中出现过的身影。

看过了BeanDefinitionParserDelegate之后,下面就来看看#parseBeanDefinitions()方法的定义吧:

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
			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;
					String namespaceUri = ele.getNamespaceURI();
					if (delegate.isDefaultNamespace(namespaceUri)) {
						// 解析默认的标签
						parseDefaultElement(ele, delegate);
					} else {
						// 解析不是在默认命名空间的
						delegate.parseCustomElement(ele);
					}
				}
			}
		} else {
			// 解析不是在默认命名空间的
			delegate.parseCustomElement(root);
		}
	}


下面是#parseDefaultElement()的定义:

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		// <import>的处理
		if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		// <alias>的处理
		else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		// <bean>的处理
		else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
	}


#parseDefaultElement()包含了<beans>标签的所有子标签的处理。

剩下的内容下次再说。:)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics