Spring解析和注册BeanDefinitions-第4课时

通过前面几课时的学习,下面我们来了解Spring的解析和注册。

XmlBeanDefinitionReader.java

<code>/**
\t * Register the bean definitions contained in the given DOM document.
\t * Called by {@code loadBeanDefinitions}.
\t *

Creates a new instance of the parser class and invokes
\t * {@code registerBeanDefinitions} on it.
\t * @param doc the DOM document
\t * @param resource the resource descriptor (for context information)
\t * @return the number of bean definitions found
\t * @throws BeanDefinitionStoreException in case of parsing errors
\t * @see #loadBeanDefinitions
\t * @see #setDocumentReaderClass
\t * @see BeanDefinitionDocumentReader#registerBeanDefinitions
\t */
\tpublic int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
\t\t//实例化
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
\t\t//记录当前BeanDefinition加载个数
int countBefore = getRegistry().getBeanDefinitionCount();
//加载注册bean
\t\tdocumentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//记录本次加载BeanDetainition个数
\t\treturn getRegistry().getBeanDefinitionCount() - countBefore;
\t}

/<code>

参数doc是通过loadBeanDefinitions加载转化。BeanDefinitionDocumentReader是一个接口,实现类的工厂是createBeanDefinitionDocumentReader。documentReader.registerBeanDefinitions,的实现类是DefaultBeanDefinitionDocumentReader,代码如下:

<code>/**
\t * This implementation parses bean definitions according to the "spring-beans" XSD
\t * (or DTD, historically).
\t *

Opens a DOM Document; then initializes the default settings
\t * specified at the {@code <beans>} level; then parses the contained bean definitions.
\t */
\t@Override
\tpublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
\t\tthis.readerContext = readerContext;
\t\tlogger.debug("Loading bean definitions");
\t\tElement root = doc.getDocumentElement();
\t\tdoRegisterBeanDefinitions(root);
\t}

/<code>

我们不难发现其真实的注册方法是doRegisterBeanDefinitions(root),如下:

<code>/**
\t * Register each bean definition within the given root {@code <beans>} element.
\t */
\tprotected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
\t\t// order to propagate and preserve <beans> default-* attributes correctly,
\t\t// keep track of the current (parent) delegate, which may be null. Create
\t\t// the new (child) delegate with a reference to the parent for fallback purposes,
\t\t// then ultimately reset this.delegate back to its original (parent) reference.
\t\t// this behavior emulates a stack of delegates without actually necessitating one.
//处理解析
\t\tBeanDefinitionParserDelegate parent = this.delegate;
\t\tthis.delegate = createDelegate(getReaderContext(), root, parent);
\t\tif (this.delegate.isDefaultNamespace(root)) {
//处理profile属性
\t\t\tString profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
\t\t\tif (StringUtils.hasText(profileSpec)) {
\t\t\t\tString[] specifiedProfiles = StringUtils.tokenizeToStringArray(
\t\t\t\t\t\tprofileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
\t\t\t\tif (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t}
\t\t}
//解析前处理,实现方法在类种是空方法,可用继承模板设计方法
\t\tpreProcessXml(root);
\t\tparseBeanDefinitions(root, this.delegate);
//解析后处理
\t\tpostProcessXml(root);
\t\tthis.delegate = parent;
\t}/<beans>/<beans>/<code>

我们注意到String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); 这行代码主要是配置环境用于生产环境和开发环境,切换开发部署环境,也可用与切换不同的数据库。集成设置如下:

<code><beans>
<beans>

<context-param>
\t<param-name>spring.profiles.active/<param-name>
<param-value>dev/<param-value>
/<context-param> /<code>

下面我们看parseBeanDefinitions(root, this.delegate)的实现;

<code>/**
\t * Parse the elements at the root level in the document:
\t * "import", "alias", "bean".
\t * @param root the DOM root element of the document
\t */
\tprotected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
\t //开始
if (delegate.isDefaultNamespace(root)) {
\t\t\tNodeList nl = root.getChildNodes();
\t\t\tfor (int i = 0; i < nl.getLength(); i++) {
\t\t\t\tNode node = nl.item(i);
\t\t\t\tif (node instanceof Element) {
\t\t\t\t\tElement ele = (Element) node;
\t\t\t\t\tif (delegate.isDefaultNamespace(ele)) {
//bean处理
\t\t\t\t\t\tparseDefaultElement(ele, delegate);
\t\t\t\t\t}
\t\t\t\t\telse {
//bean处理
\t\t\t\t\t\tdelegate.parseCustomElement(ele);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\telse {
//bean处理
\t\t\tdelegate.parseCustomElement(root);
\t\t}
\t}/<code>

对bean进行定义,Spring支持如:

<bean>

<alias>

<import>

节点如果是默认命名空进的采用parseDefaultElement方法解析,否则适用delegate.parseCustomElement(root)自定义命名空进进行接卸。判断是否是默认命名空间

<code>\tpublic static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";

//判断是否是默认命名空进
public boolean isDefaultNamespace(String namespaceUri) {
\t\treturn (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
\t}/<code>

下章讲标签的解析,也就是后续的方法parseDefaultElement:如下:


Spring解析和注册BeanDefinitions-第4课时


分享到:


相關文章: