阅读spring源码,能学习到很多设计思想,自己实际工作中也经常使用到了spring技术,但仅仅是停留在使用阶段,这次有机会去深入学习,源码分析是一件非常困难的事,自己能力水平有限,下文只是在别人的理解基础上学习。
概念:
对象阶段:
java对象经历阶段:对象定义、对象实例化、对象的使用。
Bean定义方式:
1)基于xml配置方式
2)基于annotation配置方式
3)基于java code配置方式
4)用户自定义配置方式
这里主要分析Spring Ioc容器解析基于xml配置方式的bean definition的源码实现。
spring大部分功能都是以配置文件作为切入点来实现,所以spring-beans源码分析的思路过程:对xml文档加载和解析并注册bean.
xml加载解析准备阶段
XmlBeanFactory
对资源文件进行封装
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//1)封装资源文件
//2)获取输入流
//3)根据resource 获取inputStream 并构造inputSource
//4)调用函数
this.reader.loadBeanDefinitions(resource);
}
对不同资源文件加载,Resource接口都有相应的实现:
1)文件:FileSystemResource
2)classpath资源:ClassPathResource
3)URL资源:UrlResource
4)InputStream资源:InputStreamResource
5)byte数组:ByteArrayResource
XmlBeanDefinitionReader
数据准备阶段
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//EncodedResource将资源文件进行编码处理
//设置相应的编码属性,spring会使用相应的编码作为输入流的编码
return loadBeanDefinitions(new EncodedResource(resource));
}
从Resource获取inputStream来构造inputSource
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
InputStream inputStream = encodedResource.getResource().getInputStream();
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
核心处理部分:
将xml资源文件转换成java对象document
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//获取对xml文件的验证模式
int validationMode = getValidationModeForResource(resource);
//加载xml文件,并得到对应的document
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
}
----------
XML验证模式:
1)DTD:document type definition
文档结构:元素定义的规则、元素间关系的定义规则、元素可使用的属性、可使用的实体或符号规则
2)XSD: xml schemas definition
通过xml schema指定一个xml文档所允许的结构和内容,并可检测一个xml文档是否是有效的,可用通过的xml解析器来解析。
3)通过判断是否包含doctype yes:DTD no:XSD
验证方式:XmlValidationModeDetector
public int detectValidationMode(InputStream inputStream) throws IOException {
// Peek into the file to look for DOCTYPE.
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
boolean isDtdValidated = false;
String content;
while ((content = reader.readLine()) != null) {
content = consumeCommentTokens(content);
//如果读取的行是空或者是注释则略过
if (this.inComment || !StringUtils.hasText(content)) {
continue;
}
if (hasDoctype(content)) {
isDtdValidated = true;
break;
}
//读取到<开始符号,验证模式一定会在开始符号之前
if (hasOpeningTag(content)) {
// End of meaningful data...
break;
}
}
return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
}
catch (CharConversionException ex) {
// Choked on some character encoding...
// Leave the decision up to the caller.
return VALIDATION_AUTO;
}
finally {
reader.close();
}
}
----------
将资源文件xml转换成java对象document
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
//解析inputSource
return builder.parse(inputSource);
}
----------
loadDocument方法中参数EntityResolver:
在SAX应用程序中需要实现自定义处理外部实体,所以需要实现接口并使用setEntityResolver方法向SAX驱动器注册实例。
----------
提取并注册bean
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//设置环境变量 documentReader.setEnvironment(getEnvironment());
//记录统计前beanDefinition加载的个数
int countBefore = getRegistry().getBeanDefinitionCount();
//加载及注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回本次加载的beanDefinition个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
根据返回的document注册bean信息
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//提取root 将root作为参数继续beanDefinition的注册
Element root = doc.getDocumentElement();
//解析阶段
doRegisterBeanDefinitions(root);
}
解析阶段
protected void doRegisterBeanDefinitions(Element root) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
//专门处理解析
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(this.readerContext, root, parent);
//解析前处理
preProcessXml(root);
//解析过程
parseBeanDefinitions(root, this.delegate);
//解析后处理
postProcessXml(root);
this.delegate = parent;
}
解析过程
spring的xml配置里面有两种bean声明方式:
1)默认<bean id class/>
2)自定义 <tx:annotation-driven/>
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;
if (delegate.isDefaultNamespace(ele)) {
//spring自定义bean声明方式
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
解析ele nodeName属性,根据解析出的属性名,调用对应的方法
1)元素类型 import alias beans bean
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)) {
//解析bean 调用
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
1)根据自身属性查找BeanDefinitionRegistry对象registry以便得到的Bean注册到一个容器中,供spring统一处理
2)根据beanName查询registry的BeanDefinitionMap容器
将BeanName 和 BeanDefinition以键值对形式存入beanDefinitionMap容器
3)spring容器发送一个ReaderEventListener事件
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//BeanDefinitionHolder对象 属性:beanName 和String[] aliases
//解析bean 根据定义的id 和 name属性,并根据解析值设置beanName和aliases值
//beanName 和 aliases中所有属性名加入到userNames容器中
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);
}
//发送事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
根据ele对象 解析其class 和 parent属性
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
}
xml文档解析完并注册bean,放入beanDefinitionMap容器,并发送一个ReaderEventListener事件
在web.xml配置事件监听
<!-- Spring监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>