spring源码解读(1)-容器基本实现
2017-07-25 21:23
495 查看
学习spring源码对理解spring的执行流程,如何更好的发挥spring的功能有很大的指导作用。下面针对spring加载bean容器学习spring的执行流程。
spring通过调用xml配置文件,解析并加载Bean,xmlBeanDefinitionReader则是整个资源加载的切入点:
spring从xmlBeanReader读取BeanDifinition(Bean定义实体),首先使用encodedResouce进行封装,对resource进行编码设置;然后通过resource封装的输入流getinputStream,获得InputSource(sax-simple API XML的输入源);关键逻辑doLoadBeanDefinitions(inputsource,resource)实现实体bean的加载。
往下执行,要查询xml的验证模式,加载xml文件,转化为document对象,根据document对象注册Bean;
xml文件的验证模式验证xml文件的正确性,分为两种,DTD(document type definition)文档类型定义,比较xml和DTD检查文档是否符合规范,元素和标签是否正确,主要包括,元素定义规则,元素间关系规则,可使用属性、实体和符号规则。XSD(XML Schema Definition),检验的方式主要通过声明命名空间和文档存储位置。
从上图可以看出,验证xml,首先获取EntityResourlver对象,解析xml,SAX首先读取XML文档上的声明,根据声明寻找DTD,默认从网络上寻找DTD声明,但是一旦网络出现问题,将无法顺利进行,EntityResolver的作用就是在本地保存DTD的声明。它的加载过程,首先获得抽象容器定义加载器获得资源加载器ResourceLoader,将resourceLoader作为参数加载EntityResourlver。
获取xml验证模式:getValidationModeForResource(reousrce),主要有两种验证模式,手动验证和自动验证:
/**
* Gets the validation mode for the specified {@link Resource}. If no explicit
* validation mode has been configured then the validation mode is
* {@link #detectValidationMode detected}.
* <p>Override this method if you would like full control over the validation
* mode, even when something other than {@link #VALIDATION_AUTO} was set.
*/
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;
}
接下来就是加载document对象,首先创建document构建类的工厂,获得documentBuilder,然后对inputsource进行解析parse(inputSource),解析过程为SchemaValidation的复位,document的解析:
/**
* parse
*
* @param inputSource
*
* @exception XNIException
* @exception java.io.IOException
*/
public void parse(XMLInputSource inputSource)
throws XNIException, IOException {
// null indicates that the parser is called directly, initialize them
if (securityManager == null) {
securityManager = new XMLSecurityManager(true);
fConfiguration.setProperty(Constants.SECURITY_MANAGER, securityManager);
}
if (securityPropertyManager == null) {
securityPropertyManager = new XMLSecurityPropertyManager();
fConfiguration.setProperty(Constants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager);
}
reset();
fConfiguration.parse(inputSource);
} // parse(XMLInputSource
最后通过document的验证器返回document对象: Document doc = domParser.getDocument();
最后一步,解析和注册bean:
源码与解析:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//使用defaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//记录当前beanDefiniton加载个数
int countBefore = getRegistry().getBeanDefinitionCount();
//加载并注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//记录本次加载的beanDefinition个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
其中最核心的是加载注册bean:documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
/**
* This implementation parses bean definitions according to the "spring-beans" XSD
* (or DTD, historically).
* <p>Opens a DOM Document; then initializes the default settings
* specified at the {@code <beans/>} level; then parses the contained bean definitions.
*/
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//获取document的根节点
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
默认方法解析:
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
【总结】
源码只是粗略的了解了xml加载bean的过程,都说,源码是设计模式的集合体,希望通过接下来的研究能够将隐藏在其中的设计模式逐渐读懂!
spring通过调用xml配置文件,解析并加载Bean,xmlBeanDefinitionReader则是整个资源加载的切入点:
spring从xmlBeanReader读取BeanDifinition(Bean定义实体),首先使用encodedResouce进行封装,对resource进行编码设置;然后通过resource封装的输入流getinputStream,获得InputSource(sax-simple API XML的输入源);关键逻辑doLoadBeanDefinitions(inputsource,resource)实现实体bean的加载。
往下执行,要查询xml的验证模式,加载xml文件,转化为document对象,根据document对象注册Bean;
xml文件的验证模式验证xml文件的正确性,分为两种,DTD(document type definition)文档类型定义,比较xml和DTD检查文档是否符合规范,元素和标签是否正确,主要包括,元素定义规则,元素间关系规则,可使用属性、实体和符号规则。XSD(XML Schema Definition),检验的方式主要通过声明命名空间和文档存储位置。
从上图可以看出,验证xml,首先获取EntityResourlver对象,解析xml,SAX首先读取XML文档上的声明,根据声明寻找DTD,默认从网络上寻找DTD声明,但是一旦网络出现问题,将无法顺利进行,EntityResolver的作用就是在本地保存DTD的声明。它的加载过程,首先获得抽象容器定义加载器获得资源加载器ResourceLoader,将resourceLoader作为参数加载EntityResourlver。
获取xml验证模式:getValidationModeForResource(reousrce),主要有两种验证模式,手动验证和自动验证:
/**
* Gets the validation mode for the specified {@link Resource}. If no explicit
* validation mode has been configured then the validation mode is
* {@link #detectValidationMode detected}.
* <p>Override this method if you would like full control over the validation
* mode, even when something other than {@link #VALIDATION_AUTO} was set.
*/
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;
}
接下来就是加载document对象,首先创建document构建类的工厂,获得documentBuilder,然后对inputsource进行解析parse(inputSource),解析过程为SchemaValidation的复位,document的解析:
/**
* parse
*
* @param inputSource
*
* @exception XNIException
* @exception java.io.IOException
*/
public void parse(XMLInputSource inputSource)
throws XNIException, IOException {
// null indicates that the parser is called directly, initialize them
if (securityManager == null) {
securityManager = new XMLSecurityManager(true);
fConfiguration.setProperty(Constants.SECURITY_MANAGER, securityManager);
}
if (securityPropertyManager == null) {
securityPropertyManager = new XMLSecurityPropertyManager();
fConfiguration.setProperty(Constants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager);
}
reset();
fConfiguration.parse(inputSource);
} // parse(XMLInputSource
最后通过document的验证器返回document对象: Document doc = domParser.getDocument();
最后一步,解析和注册bean:
源码与解析:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//使用defaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//记录当前beanDefiniton加载个数
int countBefore = getRegistry().getBeanDefinitionCount();
//加载并注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//记录本次加载的beanDefinition个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
其中最核心的是加载注册bean:documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
/**
* This implementation parses bean definitions according to the "spring-beans" XSD
* (or DTD, historically).
* <p>Opens a DOM Document; then initializes the default settings
* specified at the {@code <beans/>} level; then parses the contained bean definitions.
*/
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//获取document的根节点
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. //解析器--专门处理解析 BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { //处理profile属性 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.isInfoEnabled()) { logger.info("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; }
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //对beans的处理 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)) { //对bean的处理,如果是默认命名空间采用该方法解析 parseDefaultElement(ele, delegate); } else { //对bean处理,自定义方法命名空间 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
默认方法解析:
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
【总结】
源码只是粗略的了解了xml加载bean的过程,都说,源码是设计模式的集合体,希望通过接下来的研究能够将隐藏在其中的设计模式逐渐读懂!
相关文章推荐
- spring源码--容器的基本实现
- 【Spring源码分析系列】搭建Spring实现容器的基本实现
- Spring 源码深入解析(1)之bean容器的基本实现(二)
- spring源码附录(3)容器的基本实现
- Spring源码解读 :Ioc容器实现DefaultBeanDefinitionDocumentReader篇(六)
- 【Spring源码分析系列】结构组成和容器的基本实现
- Spring源码解读 :IOC容器实现BeanDefinitionReader篇(四)
- 创建ApplicationContext与BeanFactory时的区别-Spring源码学习之容器的基本实现
- spring源码初步学习-容器(BeanFactory)基本实现
- Spring源码解读 :Ioc容器实现XmlBeanDefinitionReader篇(五)
- 创建ApplicationContext与BeanFactory时的区别-Spring源码学习之容器的基本实现
- Spring源码解析-容器的基本实现
- spring源码初步学习-自己实现的ioc容器结构
- Spring源码分析----IoC容器其他特性的设计与实现
- Spring2.5源码解读 之 基于annotation的Controller实现原理分析(1)
- 1000行代码读懂Spring(一)- 实现一个基本的IoC容器
- 【Spring源码--IOC容器的实现】(二)BeanDefinition的Resource定位
- Spring2.5源码解读 之 基于annotation的Controller实现原理分析(1)
- 【Spring源码--IOC容器的实现】(三)BeanDefinition的载入和解析【I】
- 【Spring源码--IOC容器的实现】(四)BeanDefinition的注册