首先感谢 《Spring源码深度解析》郝佳,让我对spring源码有了更深的理解,本篇文章主要是对《Spring源码深度解析》解读的笔记以及自己对书本解读后的理解
1.DefaultListtableBeanFactory(bean组件的两个核心类)
XmlBeanFactory继承DefaultListtableBeanFactory,DefaultListtableBeanFactory是整个bean加载的核心,与XmlBeanFactory不同的是XmlBeanFactory中使用了自定义的XML读取器XmlBeanDefintion实现了个性化的BeanDefintion读取。
DefaultListtableBeanFactory继承了AbstractAutowireCapableBeanFactoty 并实现了 ConfigurableListtableBeanFactory以及BeanDefinitionRegistry接口
ConfigurableListtableBeanFactory 的层次结构图如下:
a、AliasRegistry:定义对alias的简单增删改操作
b、SimpleAliasRegistry:主要使用Map作为alias的缓存,并对接口AliasRegistry进行实现
c、SingLetonBeanRegisty:定义对单例的注册以及获取
d、BeanFactory:定义获取bean及bean的各种属性
e、DefaultSingletonBeanRegistry:对接口SingletonBeanRegistry和函数的实现
f、FactoryBeanRegistySupport:在DefaultSingletonBeanRegistry基础上增加对Factory的特殊处理
g、ConfigurableBeanFactory:提供配置Factory的各种方法
h、ListableBeanFactory:根据各种条件获取bean的配置清单
i、AbstractBeanFactory:综合AbstractBeanFactory 并对接口Autowire CapableBeaFactory进行实现
j、ConfigurableListableBeanFactory:BeanFactoryb配置清单,指定忽略类型及接口等
k、DefaultListtableBeanFactory:综合上面的所有功能
2.XmlBeanDefinitionReader(bean组件的两个核心类)
XML配置文件的读取Spring中重要的功能。可以从XmlBeanDefinitionReader中梳理资源文件读取、解析以及注册;各类用法如下
a、ResourceLoader:定义资源加载器、主要应用于根据给定的资源文件地址返回的Resource
b、BeanDefinitionReader:主要定义资源文件读取并转换为BeanDefinition 的各个功能
c、EnvironmentCapable:定义获取Environment 方法
d、DocumentLoader:定义资源文件加载到转换为Document的功能
e、AbstractBeanDefinitionReader:对EnvironmentCapable、BeanDefinitionReader类定义的功能进行实现
f、BeanDefinitionDocumentReader:定义读取Document并注册BeanDefinition功能
g、BeanDefinitionParserDelegate:定义解析Element的各种方法
整个XML配置文件读取数据的大致流程(在XmlBeanDefinitionReader包含的几个处理)
a、通过继承自AbstractBeanDefinitionReader中的方法,使用ResourceLoader将资源文件路径转换为Resource文件
b、通过Document将Resource文件转换为Document文件
c、通过BeanDefinitionReader的实现类DefaultBeanDefinitionReader对Element·进行解析
3.容器的基础XmlBeanFactory
a、配置文件封装
Spring的配置文件读取是通过ClassPathResource进行封装的,在java中将不同来源的资源抽象成URL,通过注册不同的handle来处理不同来源的资源的读取逻辑,
handle的类型通过使用不通的前缀(协议)来识别,如“file”、“http”、“jar”等。而URL没有默认定义的相对Classpath或ServletContext等资源的handler,需要了解
URL实现机制来自己注册URLStreamHandler来解析特定的URL前缀。因此Spring对其内部使用到的资源实现了自己的抽象结构:Resource接口来封装底层资源
源码:
public interface InputStreamSource {
//返回一个新的InputStream对象
public abstract InputStream getInputStream() throws IOException;
}
public interface Resource extends InputStreamSource {
//是否存在
public abstract boolean exists();
//是否可读
public abstract boolean isReadable();
//是否打开
public abstract boolean isOpen();
//获取URL
public abstract URL getURL() throws IOException;
//获取URI
public abstract URI getURI() throws IOException;
//获取File
public abstract File getFile() throws IOException;
//获取长度
public abstract long contentLength() throws IOException;
//获取lastModified属性
public abstract long lastModified() throws IOException;
//基于当前资源创建一个相对资源
public abstract Resource createRelative(String s) throws IOException;
//获取文件名
public abstract String getFilename();
//错误处理中打印信息
public abstract String getDescription();
}
对于不同的资源都有不同的实现:如文件、classpath资源等,Resource完成对配置文件进行封装后读取的工作全权交给了XmlBeanDefinitionReader
b、加载Bean
在XmlBeanFactory的初始化有多个方法,在其中有一个使用Resource实例作为构造函数参数的方法,源码如下
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//整个资源加载的切入点
this.reader.loadBeanDefinitions(resource);
}
//构造函数中this.reader.loadBeanDefinitions(resource);是资源加载的真正实现,在这之前还调用了父类构造方法初始化过程super(parentBeanFactory);
public AbstractAutowireCapableBeanFactory() {
super();
//自动装配功能
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
this.reader.loadBeanDefinitions(resource);整个资源加载的切入点方法的时序
①:封装资源文件。进入XmlBeanDefinitionReader后首先对Resource使用EncodeResource的Resource类进行封装(编码)
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
EncodeResource主要用于对文件的编码进行处理,其中主要体现在getReader()方法中
public Reader getReader() throws IOException {
if (this.charset != null) {
return new InputStreamReader(this.resource.getInputStream(), this.charset);
}
else if (this.encoding != null) {
return new InputStreamReader(this.resource.getInputStream(), this.encoding);
}
else {
return new InputStreamReader(this.resource.getInputStream());
}
}
②:获取输入流:从Resource中获取对应的InputStream并构造InputSource
③:在构造InputSource 实例个Resource实例继续调用都LoadBeanDefinition
LoadBeanDefinition方法是真正的数据准备阶段,源码如下
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<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
//在得到经过EncodeResource封装过的Resource来获取InputStream
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) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
doLoadBeanDefinitions方法做了三件事
①:获取XML文件的验证模式
②:加载XML,获取Document对象
③:根据返回的Document注册Bean
源码如下
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//得到Document 对象
Document doc = doLoadDocument(inputSource, resource);
//注册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(),
"XMLdocument 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,返回Document对象
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
//得到验证模式
protected int getValidationModeForResource(Resource resource) {
int validationModeToUse = getValidationMode();
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
int detectedMode = detectValidationMode(resource);
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
// Hmm, we didn't get a clear indication... Let's assume XSD,
// since apparently no DTD declaration has been found up until
// detection stopped (before finding the document's root tag).
return VALIDATION_XSD;
}