您的位置:首页 > 编程语言 > Java开发

spring源码之XmlBeanDefinitionReader与bean的注册

2013-09-24 15:57 429 查看
终于开始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文件的定义:

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd ">

<bean id="say1" class="fjs.Say">
<property name="name" value="fjs"   />
</bean>

<bean id="fjs" class="fjs.Fjs">
</bean>

<aop:config>

<aop:aspect ref="fjs">
<aop:pointcut id="haha" expression="execution(* fjs.Say.saying(..))" />
<aop:before pointcut-ref="haha" method="before"  />
<aop:after pointcut-ref="haha" method="after"  />
</aop:aspect>

</aop:config>
</beans>


上面还有一部分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到底是怎么读取数据的,还是先来看看它的继承体系吧:



这里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<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(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吧。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐