spring源码学习系列2.1-从xml到document

本章探讨从xml到document的过程-[color=red]xml文件生成document类[/color]

[color=red]从xml到document[/color]

从document到beanDefinition

从beanDefiniton到instance


在<spring源码学习系列2.2-从document到beanDefinition>中,

"
三是注册到beanDefinition容器
// Register the final decorated instance.  
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

"

对这里getReaderContext().getRegistry()有些疑惑,getReaderContext()是什么?getRegistry()是什么?限于篇幅,这里进行释疑。

在堆栈从[color=red]xml到document[/color]的过程中,可以得到上面疑惑的解答。

对于从[color=red]document到beanDefinition[/color]以及[color=red]beanDefinition到instance[/color]的过程,请参见:
<spring源码学习系列2.2-从document到beanDefinition>
<spring源码学习系列2-从beanDefinition到instance>


涉及的源码类:
org.springframework.web.context.ContextLoaderListener

org.springframework.web.context.ContextLoader

org.springframework.web.context.ConfigurableWebApplicationContext


[size=large]xml到document[/size]

web项目启动spring容器的入口在web.xml中,
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>


ContextLoaderListener源码:
[url]http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.web/3.2.2/org/springframework/web/context/ContextLoaderListener.java[/url]

该类的部分信息为:
ContextLoaderListener extends ContextLoader implements ServletContextListener
执行初始化方法的入口:
/**
* Initialize the root web application context.
*/
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
this.contextLoader.initWebApplicationContext(event.getServletContext());
}


contextLoader源码:
[url]http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.web/3.2.2/org/springframework/web/context/ContextLoader.java[/url]

其将初始化委托给contextLoader.initWebApplicationContext,
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
// 创建webApplicationContext上下文环境
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
// 加载父上下文
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
// 初始化webApplicationContext上下文环境
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}



[b][size=medium]创建XmlWebApplicationContext类容器[/size][/b]

首先实例化contextClass:XmlWebApplicationContext-[size=medium][color=green]创建webApplicationContext的上下文环境[/color][/size]
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
Class<?> contextClass = determineContextClass(sc);
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}


protected Class<?> determineContextClass(ServletContext servletContext) {
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
try {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load custom context class [" + contextClassName + "]", ex);
}
}
else {
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load default context class [" + contextClassName + "]", ex);
}
}
}

在determineContextClass方法中,
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);

开发人员可以自定义配置CONTEXT_CLASS_PARAM=contextClass参数,定义自己扩展的applicationContext作为the root WebApplicationContext-[color=red][size=medium]此处可以看做spring的一种扩展[/size][/color]

如果没有配置,则从默认配置spring-web.jar/org.springframework.web.context/ContextLoader.properties中读取,
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext


然后调用contextLoader.configureAndRefreshWebApplicationContext-[size=medium][color=green]初始化上下文环境[/color][/size]
该方法里面准备上面创建的上下文环境类(ConfigurableWebApplicationContext)的环境,并委托ConfigurableWebApplicationContext做进一步初始化操作
wac.refresh();



contextLoader
-------------------------------------------------------承上启下的分割线----------------------------------------------
applicationContext
1.这里主要分析生成beanFactory部分


[color=red][size=medium]这里开始进入加载spring的实质性入口[/size][/color]

abstractApplicationContext源码:
[url]http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.context/3.2.2/org/springframework/context/support/AbstractApplicationContext.java[/url]

AbstractRefreshableApplicationContext源码:
[url]http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.context/3.2.2/org/springframework/context/support/AbstractRefreshableApplicationContext.java/[/url]

abstractApplicationContext.refresh:(abstractApplicationContext implements ConfigurableWebApplicationContext)
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
//解析xml生成beanDefinition并注册
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}
}
}


[color=red]文章主要分析xml到document的部分(实例化beanFactory的一部分),所以主要关注[/color]
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();


这行包括主要有2个操作:
[color=red][size=medium]从xml到document[/size][/color]

[size=medium]从document到beanDefinition[/size]
见:<spring源码学习系列2.2-从document到beanDefinition>


该方法里面,调用子类AbstractRefreshableApplicationContext.refreshBeanFactory()初始化beanFactory:
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

该方法中,可分为2部分:

[b][size=medium]创建DefaultListableBeanFactory(parentBeanFactory)[/size][/b]

首先创建beanFactory:
DefaultListableBeanFactory beanFactory = createBeanFactory();


AbstractRefreshableApplicationContext.createBeanFactory()
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}


abstractApplicationContext.getInternalParentBeanFactory()
protected BeanFactory getInternalParentBeanFactory() {
return (getParent() instanceof ConfigurableApplicationContext) ?
((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
}



其次就是进入到初始化doc的代码-[color=green]从这里开始可以解答开头提出的问题[/color]
loadBeanDefinitions(beanFactory);


[b][size=medium]创建XmlBeanDefinitionReader(beanFactory)[/size][/b]

具体调用子类xmlWebApplicationContext.loadBeanDefinitions
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}



初始化XmlBeanDefinitionReader,由此类读取xml文件。将beanFactory传入XmlBeanDefinitionReader,beanFactory实现了BeanDefinitionRegistry,开头的问题getRegistry()实际得到的就是beanFactory,注册beanDefinition实际上就是注册到beanFactory中。beanFactory为所有ioc容器的顶级接口。
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}


xmlWebApplicationContext#loadBeanDefinitions
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
reader.loadBeanDefinitions(configLocation);
}
}
}



applicationContext
-------------------------------------------------------承上启下的分割线----------------------------------------------
xmlBeanDefinitionReader
1.调用documentLoader生成doc
2.调用BeanDefinitionDocumentReader解析doc并生成beanDefinition

[color=red][size=medium]委托xmlBeanDefinitionReader读取xml,解析成beanDefinition,并注册到传入的beanFactory中[/size][/color]

最终通过xmlBeanDefinitionReader.doLoadBeanDefinitions加载xml(Actually load bean definitions from the specified XML file)
xmlBeanDefinitionReader#doLoadBeanDefinitions
/**
* Actually load bean definitions from the specified XML file.
* @param inputSource the SAX InputSource to read from
* @param resource the resource descriptor for the XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource);
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
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(),
"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);
}
}

首先调用this.documentLoader.loadDocument解析xml生成document类
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());

spring是通过默认的jdk工具类javax.xml.parsers.DocumentBuilder来解析xml文件的

[quote]javax.xml.parsers.DocumentBuilder


Defines the API to obtain DOM Document instances from an XML document. Using this class, an application programmer can obtain a Document from XML.

An instance of this class can be obtained from the DocumentBuilderFactory.newDocumentBuilder() method. Once an instance of this class is obtained, XML can be parsed from a variety of input sources. These input sources are InputStreams, Files, URLs, and SAX InputSources.

Note that this class reuses several classes from the SAX API. This does not require that the implementor of the underlying DOM implementation use a SAX parser to parse XML document into a Document. It merely requires that the implementation communicate with the application using these existing APIs.
Author:Jeff Suttor[/quote]


其次调用XmlBeanDefinitionReader#registerBeanDefinitions解析doc生成beanDefinition并注册
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}


委托BeanDefinitionDocumentReader解析doc并注册
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

这里创建了读取xml的上下文环境XmlReaderContext

[b][size=medium]创建XmlReaderContext[/size][/b]

XmlBeanDefinitionReader#createReaderContext
protected XmlReaderContext createReaderContext(Resource resource) {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, this.namespaceHandlerResolver);
}


public XmlReaderContext(
Resource resource, ProblemReporter problemReporter,
ReaderEventListener eventListener, SourceExtractor sourceExtractor,
XmlBeanDefinitionReader reader, NamespaceHandlerResolver namespaceHandlerResolver) {

super(resource, problemReporter, eventListener, sourceExtractor);
this.reader = reader;
this.namespaceHandlerResolver = namespaceHandlerResolver;
}


[quote]回到开头提出的问题:
getReaderContext() 获取的就是xmlReaderContext

xmlReaderContext.getRegistry() -得到的就是xmlBeanDefinitionReader.getRegistry(),即beanFactory
public final BeanDefinitionRegistry getRegistry() {
return this.reader.getRegistry();
}
[/quote]

至此,xml到document解析完成,然后就是document到beanDefintion的过程,请参考:
<spring源码学习系列2.2-从document到beanDefinition>

DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
/**
* {@inheritDoc}
* <p>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.
*/
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}


DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
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;
}
}

// 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(this.readerContext, root, parent);

preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);

this.delegate = parent;
}



涉及源码职责:
contextLoader.initWebApplicationContext(event.getServletContext())

contextLoader.createWebApplicationContext(servletContext)

contextLoader.configureAndRefreshWebApplicationContext(cwac, servletContext)

abstractApplicationContext.refresh()

abstractRefreshableApplicationContext.refreshBeanFactory

abstractRefreshableApplicationContext.createBeanFactory

xmlWebApplicationContext.loadBeanDefinitions


参考网站:
ConfigurableApplicationContext vs ApplicationContext
http://stackoverflow.com/questions/30861709/configurableapplicationcontext-vs-applicationcontext
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值