spring-framework源码——配置文件的读取

spring-framework源码——配置文件的读取

我们的配置文件很简单,只定义了一个简单java bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
		<bean id="myTestBean" class="org.springframework.MyTestBean"></bean>
</beans>

这个bean的内容是这样的

public class MyTestBean {
	private String testStr = "testStr";

	public String getTestStr() {
		return testStr;
	}

	public void setTestStr(String testStr) {
		this.testStr = testStr;
	}
}

测试类

		ClassPathResource classPathResource = new ClassPathResource("beanFactoryTest.xml");
		DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
		reader.loadBeanDefinitions(classPathResource);

总结一下这个代码做了什么,其实主要方法在reader.loadBeanDefinitions(classPathResource)中。先读取配置类,生成BeanDefinition。然后去注册这个BeanDefinition。注册其实就是在map里面加上当前这个BeanDefinition。

先看第一行new ClassPathResource("beanFactoryTest.xml"),这里就是简单得把配置文件封装成一个resource。

第二行创建一个factory对象,这里会依次去初始化他的父类对象,也没什么好说的,值得一提的是代码跟踪的父类的一个构造方法中

	public AbstractAutowireCapableBeanFactory() {
		super();
		ignoreDependencyInterface(BeanNameAware.class);
		ignoreDependencyInterface(BeanFactoryAware.class);
		ignoreDependencyInterface(BeanClassLoaderAware.class);
	}

ignoreDependencyInterface方法的说明是

* Ignore the given dependency interface for autowiring.
* <p>This will typically be used by application contexts to register
* dependencies that are resolved in other ways, like BeanFactory through
* BeanFactoryAware or ApplicationContext through ApplicationContextAware.
* <p>By default, only the BeanFactoryAware interface is ignored.
* For further types to ignore, invoke this method for each type.

大意就是忽略给定接口的自动装配功能,上面的三个接口都会被忽略。

第三行new XmlBeanDefinitionReader(factory)为给定的工厂创建XmlBeanDefinitionReader对象。

接下来进入重头戏,看看最后一行代码

reader.loadBeanDefinitions(classPathResource);

这行代码其实就可以看出做了什么,通过reader从resource中加载bean的定义。reader就是前面创建的XmlBeanDefinitionReader对象,classPathResource就是我们配置文件的封装。

首先进入loadBeanDefinitions方法

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

这里对我们传入的resource进行了一层封装,变成了EncodedResource,其实就多了encoding和charset属性。但是我们没有指定这两个属性,所以都为空。

进入这个方法,我省略了一些不重要的代码

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
   		......
		try {
            //inputStrean和下面的inputSource都不属性spring,来自org.xml.sax
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
                //主要逻辑实现
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		}
		catch (IOException ex) {
            ......
        }
		finally {
			......
			}
		}
	}

这里最重要的就是doLoadBeanDefinitions方法了,spring中以do开头的都是真正做事的。我们来看一下这个方法

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    throws BeanDefinitionStoreException {

    try {
        //获取Document,不做详细介绍,感兴趣可以自己去看代码
        Document doc = doLoadDocument(inputSource, resource);
        int count = registerBeanDefinitions(doc, resource);
        if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + count + " bean definitions from " + resource);
        }
        return count;
    }		
    catch (BeanDefinitionStoreException ex) {
        throw ex;
    }
    ......
        //后面还有各种异常

这里重点就是registerBeanDefinitions方法

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //BeanDefinitionDocumentReader是一个接口,实际实例化为DefaultBeanDefinitionDocumentReader对象
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        //记录之前BeanDefinition的数量
		int countBefore = getRegistry().getBeanDefinitionCount();
        //主要逻辑实现,加载和注册bean
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        //返回本次加载的BeanDefinition的数量
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

registerBeanDefinitions方法里面主要就是doRegisterBeanDefinitions方法,

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    doRegisterBeanDefinitions(doc.getDocumentElement());
}

protected void doRegisterBeanDefinitions(Element root) {
		//解析xml中bean的定义(因为在配置文件中可能引用其他配置文件,
    	//就会有beans中嵌套beans的情况出现,所以使用两个delegate来处理这个问题
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);
		//处理profile属性
		if (this.delegate.isDefaultNamespace(root)) {
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isDebugEnabled()) {
						logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}
		//解析前处理,留给子类实现
		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
    	//解析后处理,留给子类实现
		postProcessXml(root);

		this.delegate = parent;
	}

这里preProcessXml和postProcessXml中都是空的,其实是一种模板方法模式。

主要来看看parseBeanDefinitions(root, this.delegate)方法。

	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;
                    //根据是否是默认的标签,选择对bean解析的方法
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

由于在配置文件中可以自定义标签,所以这里需要判断标签是默认的标签,比如<bean>,还是自己定义的标签,从而选择对应的解析方法。

这里我们只探讨一下默认的标签解析

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

这里我们只看一下bean标签的处理

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //持有BeanDefinition对象,包括名字和别名
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
            //自定义标签进行解析
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				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. 委托BeanDefinitionParserDelegate进行元素解析,保存在BeanDefinitionHolder中。
  2. bdHolder不为空的情况,如果标签下的子节点有自定义标签,还需要对自定义标签进行解析
  3. 对bdHolder进行注册
  4. 发出注册事件,通知相关的监听器

其中1和3是重点,1先通过解析文件生成beanDefinition,然后再进行注册。
先来看看第一步中的parseBeanDefinitionElement方法

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
      return parseBeanDefinitionElement(ele, null);
	}
	
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        //id属性
		String id = ele.getAttribute(ID_ATTRIBUTE);
		//name属性
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
		//分割name属性(代码省略)
		......

		String beanName = id;
        //在没有指定beanName时使用别名
		......
        //确保bean的名字没有重复
        if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
                //如果不存在beanName,那么根据spring中的命名规则为当前bean生成对应的bean
				...
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
            //返回BeanDefinitionHolder
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

这个函数最后返回了一个BeanDefinitionHolder,里面有我们需要的beanDefinition等信息。我们来看一下beanDefinition是如何解析的。记住这里返回了一个BeanDefinitionHolder,等一下我们还要回来。

	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {
		//用来记录状态
		this.parseState.push(new BeanEntry(beanName));

		String className = null;
        //解析class属性
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
        //解析parent属性
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
            //生成bean definition
            //将信息保存在AbstractBeanDefinition的子类-GenericBeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			//硬编码解析默认bean的各种属性,可能有十多种吧
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
			//解析元数据
			parseMetaElements(ele, bd);
			//解析lookup-method属性
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //解析replace-method属性
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			//解析构造函数参数
			parseConstructorArgElements(ele, bd);
            //解析property子元素
			parsePropertyElements(ele, bd);
            //解析qualifier子元素
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		catch (ClassNotFoundException ex) {
			//省略各种异常
		}
		finally {
			this.parseState.pop();
		}
	
		return null;
	}

通过createBeanDefinition()生成AbstractBeanDefinition,然后对这个对象进一步解析,来看看createBeanDefinition方法

	protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
			throws ClassNotFoundException {

		return BeanDefinitionReaderUtils.createBeanDefinition(
				parentName, className, this.readerContext.getBeanClassLoader());
	}

BeanDefinitionReaderUtils

	public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

		GenericBeanDefinition bd = new GenericBeanDefinition();
		bd.setParentName(parentName);
		if (className != null) {
			if (classLoader != null) {
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}

GenericBeanDefinition里面定义了parentName的成员变量,在我们的例子中,parentName为null,程序会执行bd.setBeanClassName(className),这里className是我们配置文件定义的class全限定名。

至此,我们拿到了一个简单的AbstractBeanDefinition,后面根据各个属性对AbstractBeanDefinition进行完善,这里就不详细讲了。

我们回到前面的代码

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //持有BeanDefinition对象,包括名字和别名
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
            //自定义标签进行解析
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				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));
		}
	}

前面说了这个函数主要做了四件事,我们刚才解析了BeanDefinitionHolder的获得过程,先获得AbstractBeanDefinition,然后用BeanDefinitionHolder封装这个BeanDefinition,得到了这个BeanDefinitionHolder。

第二步,对自定义标签的解析这里就不看了,其实就是对BeanDefinition进行更进一步的封装。

第三步,注册BeanDefinition,我们来看看代码

	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Register bean definition under primary name.
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}

解析出来的BeanDefinition会注册到BeanDefinitionRegistry类型的实例registry中,可以看到这里有两个部分,注册BeanDefinition和注册别名。先看一下BeanDefinition的注册。

@Override
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属性中的methodOverrides校验,
          //校验methodOverrides是否与工厂方法并存或者methodOverrides对应的方法根本不存在
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex);
      }
   }

   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    
   if (existingDefinition != null) {
       //处理bean已经注册的情况
       //beanName已经注册,但是配置中设置不允许覆盖,则抛出异常
      if (!isAllowBeanDefinitionOverriding()) {
         throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }
      else if (existingDefinition.getRole() < beanDefinition.getRole()) {
         // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
         if (logger.isInfoEnabled()) {
            logger.info("Overriding user-defined bean definition for bean '" + beanName +
                  "' with a framework-generated bean definition: replacing [" +
                  existingDefinition + "] with [" + beanDefinition + "]");
         }
      }
      else if (!beanDefinition.equals(existingDefinition)) {
         if (logger.isDebugEnabled()) {
            logger.debug("Overriding bean definition for bean '" + beanName +
                  "' with a different definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      else {
         if (logger.isTraceEnabled()) {
            logger.trace("Overriding bean definition for bean '" + beanName +
                  "' with an equivalent definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
       //覆盖bean
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
       //bean没有注册过
       //检查这个工厂的bean是不是已经开始创建了,如果是,则要考虑并发的情况
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
             //这里其实就是做了三个操作,只是需要考虑并发,所以都是先复制,再进行增加或删除操作
             //三个操作其实就是下面else部分里的三个操作
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
               updatedSingletons.remove(beanName);
               this.manualSingletonNames = updatedSingletons;
            }
         }
      }
      else {
         // Still in startup registration phase
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }
	//如果之前beanName已经注册了或者存在singleton的beanName,则重置这个bean对应的缓存
   if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
}

这个方法在DefaultListableBeanFactory这个类中,可见这是一个比较重要的类。

在spring4.2.x或者之前的代码中,后面对bean的注册的整段代码都是放在synchronized内的。在后面的版本中对其进行了优化,提高了效率。上面的bean注册主要进行了几个步骤:

  1. 对AbstractBeanDefinition进行校验,主要针对AbstractBeanDefinition的methodOverrides属性。

  2. 对beanName已经注册情况的处理。如果设置了不允许bean的覆盖,则抛出异常,否则覆盖,并根据具体情况显示日志。

  3. bean不存在的话

    3.1 如果还处在启动阶段,那很简单,更新beanDefinitionMap,beanDefinitionNames和manualSingletonNames即可

    3.2 如果这个工厂的bean是不是已经开始创建了,则要考虑并发,对beanDefinitionNames和manualSingletonNames的增加和删除操作也要注意。

  4. 如果之前beanName已经注册了或者存在singleton的beanName,则重置这个bean对应的缓存。

然后我们再来看一下别名的注册。由于在这个例子里面没有别名,所以没法跟踪。我们就看一下SimpleAliasRegistry这个类中的方法,我把一些log相关的代码删掉了。

	@Override
	public void registerAlias(String name, String alias) {
		Assert.hasText(name, "'name' must not be empty");
		Assert.hasText(alias, "'alias' must not be empty");
		synchronized (this.aliasMap) {
			if (alias.equals(name)) {
				this.aliasMap.remove(alias);
			}
			else {
				String registeredName = this.aliasMap.get(alias);
                //如果registeredName有值,则说明之前存在了。
				if (registeredName != null) {
					if (registeredName.equals(name)) {
						// An existing alias - no need to re-register
						return;
					}
					if (!allowAliasOverriding()) {
						throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
								name + "': It is already registered for name '" + registeredName + "'.");
					}
				}
                //alias循环检测
				checkForAliasCircle(name, alias);
                //注册alias
				this.aliasMap.put(alias, name);
				}
			}
		}
	}

其实注册最终就是在aliasMap中添加一个数据,但是在添加之前要经过一系列的验证:

  1. 如果beanName和aliasName一样,则把这个aliasName删掉。
  2. 别名已经注册过的情况。如果注册的aliasName指向的beanName和当前的beanName一样,则说明这个bean已经注册过了,直接返回;如果aliasName指向另一个beanName,则看是否设置可以覆盖,不能的话抛出异常,否则就覆盖。
  3. alias循环检测.
  4. 注册alias

完成了beanDefinition的注册,算是完成了前面四部曲的前三步,还记得第四步吗?发送注册事件。

// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

public void fireComponentRegistered(ComponentDefinition componentDefinition) {
    this.eventListener.componentRegistered(componentDefinition);
}

继续跟踪进去发现是空的。

这个实现其实只是为了扩展,如果开发人员需要对注册BeanDefinition事件进行监听的话,可以将处理逻辑写到监听器中,目前spring中并没有对此事件进行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值