终于开始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到底是怎么读取数据的,还是先来看看它的继承体系吧:
这里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吧。。。