如何在web容器中加载过程?

如何在web容器中加载过程?

首先从WEB.XML入手

==>web.xml


代码

<context-param>
<param-name>webAppRootKey</param-name>
<param-value>task.root</param-value>
</context-param>
<!--定义SPRING配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/taskContext*.xml</param-value>
</context-param>
</span>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<!--定义LOG4J监听器-->
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

<!--定义SPRING监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>



进入contextLoaderListener看看到底加载时做了甚么
==>org.springframework.web.context.ContextLoaderListener


代码

publicclassContextLoaderListenerimplementsServletContextListener{

privateContextLoadercontextLoader;

/**
*Initializetherootwebapplicationcontext.
*/
//当WEB上下文初始化时,系统会调用此方法
publicvoidcontextInitialized(ServletContextEventevent){
this.contextLoader=createContextLoader();

//监听到WEB上下文初始化的时候执行SPRING上下文contextLoader的初始化工作
this.contextLoader.initWebApplicationContext(event.getServletContext());
}


/**
*CreatetheContextLoadertouse.Canbeoverriddeninsubclasses.
*
@returnthenewContextLoader
*/
protectedContextLoadercreateContextLoader(){
returnnewContextLoader();
}


/**
*ReturntheContextLoaderusedbythislistener.
*/
publicContextLoadergetContextLoader(){
returncontextLoader;
}


/**
*Closetherootwebapplicationcontext.
*/
publicvoidcontextDestroyed(ServletContextEventevent){
if(this.contextLoader!=null){
this.contextLoader.closeWebApplicationContext(event.getServletContext());
}
}

}


看一下是怎么来初始化webapplicationContext的

==>contextLoader.initWebApplicationContext


代码

publicWebApplicationContextinitWebApplicationContext(ServletContextservletContext)
throwsIllegalStateException,BeansException{

if(servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)!=null){
thrownewIllegalStateException(
"Cannotinitializecontextbecausethereisalreadyarootapplicationcontext

present-"+
"checkwhetheryouhavemultipleContextLoader*definitionsinyourweb.xml!");
}


longstartTime=System.currentTimeMillis();
if(logger.isInfoEnabled()){
logger.info(
"RootWebApplicationContext:initializationstarted");
}
servletContext.log(
"LoadingSpringrootWebApplicationContext");

try{
//Determineparentforrootwebapplicationcontext,ifany.
ApplicationContextparent=loadParentContext(servletContext);

//Storecontextinlocalinstancevariable,toguaranteethat
//itisavailableonServletContextshutdown.

//创建web上下文
this.context=createWebApplicationContext(servletContext,parent);
servletContext.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
this.context);

if(logger.isInfoEnabled()){
logger.info(
"Usingcontextclass["+this.context.getClass().getName()+
"]forrootWebApplicationContext");
}

if(logger.isDebugEnabled()){
logger.debug(
"PublishedrootWebApplicationContext["+this.context+
"]asServletContextattributewithname["+
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE+"]");
}

if(logger.isInfoEnabled()){
longelapsedTime=System.currentTimeMillis()-startTime;
logger.info(
"RootWebApplicationContext:initializationcompletedin"+elapsedTime+"

ms");
}

returnthis.context;
}

catch(RuntimeExceptionex){
logger.error(
"Contextinitializationfailed",ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,ex);

throwex;
}

catch(Errorerr){
logger.error(
"Contextinitializationfailed",err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,err);

throwerr;
}
}



==>contextLoader.createWebApplicationContext(servletContext,parent);


代码

protectedWebApplicationContextcreateWebApplicationContext(
ServletContextservletContext,ApplicationContextparent)
throwsBeansException{
//根据servletContext来决定要实例化的WebApplicationContext
ClasscontextClass=determineContextClass(servletContext);
if(!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)){
thrownewApplicationContextException("Customcontextclass["+contextClass.getName()+
"]isnotoftypeConfigurableWebApplicationContext");
}
ConfigurableWebApplicationContextwac
=
(ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
wac.setParent(parent);
wac.setServletContext(servletContext);


//得到WEB.XML中设置的SPRING配置文件位置
StringconfigLocation=servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
if(configLocation!=null){
//把配置文件分段后设置到WebApplicationContext的ConfigLocations中
wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,
ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
}

//刷新WebApplicationContext
wac.refresh();
returnwac;
}



==>contextLoader.determineContextClass(servletContext);


代码

protectedClassdetermineContextClass(ServletContextservletContext)throwsApplicationContextException{
//获得需要实例化的CONTEXT类名,在web.xml中有设置,如果没有设置,那么为空
StringcontextClassName=servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if(contextClassName!=null){
try{
returnClassUtils.forName(contextClassName);
}

catch(ClassNotFoundExceptionex){
thrownewApplicationContextException(
"Failedtoloadcustomcontextclass["+contextClassName+"]",ex);
}
}

//如果在springweb.xml中没有设置context类位置,那么取得默认context
else{
//取得defaultStrategies配置文件中的WebApplicationContext属性
contextClassName=defaultStrategies.getProperty(WebApplicationContext.class.getName());
try{
returnClassUtils.forName(contextClassName);
}

catch(ClassNotFoundExceptionex){
thrownewApplicationContextException(
"Failedtoloaddefaultcontextclass["+contextClassName+"]",ex);
}
}
}


SPRING上下文默认的策略是甚么呢
?
==>contextLoader.defaultStrategies


代码

privatestaticfinalPropertiesdefaultStrategies;

static{
//Loaddefaultstrategyimplementationsfrompropertiesfile.
//Thisiscurrentlystrictlyinternalandnotmeanttobecustomized
//byapplicationdevelopers.
try{
//设置classpath为contextLoader同级目录
ClassPathResourceresource=newClassPathResource(DEFAULT_STRATEGIES_PATH,ContextLoader.class);
//加载该目录下的所有properties文件
defaultStrategies=PropertiesLoaderUtils.loadProperties(resource);
}

catch(IOExceptionex){
thrownewIllegalStateException("Couldnotload'ContextLoader.properties':"+ex.getMessage());
}
}


找到同级目录下的配置文件

==>ContextLoader.properties


代码
#DefaultWebApplicationContextimplementation
classforContextLoader.
#Usedasfallbackwhennoexplicitcontextimplementationhasbeenspecifiedascontext
-param.
#Notmeanttobecustomizedbyapplicationdevelopers.

#默认的WebApplicationContext为org.springframework.web.context.support.XmlWebApplicationContext
org.springframework.web.context.WebApplicationContext
=org.springframework.web.context.support.XmlWebApplicationContext


==>org.springframework.web.context.support.XmlWebApplicationContext

代码

publicclassXmlWebApplicationContextextendsAbstractRefreshableWebApplicationContext{

/**Defaultconfiglocationfortherootcontext*/

//配置了默认的spring配置文件
publicstaticfinalStringDEFAULT_CONFIG_LOCATION="/WEB-INF/applicationContext.xml";

//配置文件默认BUILD路径
publicstaticfinalStringDEFAULT_CONFIG_LOCATION_PREFIX="/WEB-INF/";

//配置文件默认后缀名
publicstaticfinalStringDEFAULT_CONFIG_LOCATION_SUFFIX=".xml";

/**
*LoadsthebeandefinitionsviaanXmlBeanDefinitionReader.
*
@seeorg.springframework.beans.factory.xml.XmlBeanDefinitionReader
*
@see#initBeanDefinitionReader
*
@see#loadBeanDefinitions
*/
//获得bean配置
protectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory)throwsIOException{
//从BEAN工厂获得一个XmlBeanDefinitionReader来读取SPRING配置文件
XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory);

//设置beanDefinitionReader服务于当前CONTEXT
//resourceloadingenvironment.
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(
newResourceEntityResolver(this));

//Allowasubclasstoprovidecustominitializationofthereader,
//thenproceedwithactuallyloadingthebeandefinitions.
initBeanDefinitionReader(beanDefinitionReader);
//读取配置文件
loadBeanDefinitions(beanDefinitionReader);
}


/**
*Initializethebeandefinitionreaderusedforloadingthebean
*definitionsofthiscontext.Defaultimplementationisempty.
*<p>Canbeoverriddeninsubclasses,e.g.forturningoffXMLvalidation
*orusingadifferentXmlBeanDefinitionParserimplementation.
*
@parambeanDefinitionReaderthebeandefinitionreaderusedbythiscontext
*
@seeorg.springframework.beans.factory.xml.XmlBeanDefinitionReader#setValidationMode
*
@seeorg.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass
*/
protectedvoidinitBeanDefinitionReader(XmlBeanDefinitionReaderbeanDefinitionReader){
}


/**
*LoadthebeandefinitionswiththegivenXmlBeanDefinitionReader.
*<p>ThelifecycleofthebeanfactoryishandledbytherefreshBeanFactorymethod;
*thereforethismethodisjustsupposedtoloadand/orregisterbeandefinitions.
*<p>DelegatestoaResourcePatternResolverforresolvinglocationpatterns
*intoResourceinstances.
*
@throwsorg.springframework.beans.BeansExceptionincaseofbeanregistrationerrors
*
@throwsjava.io.IOExceptioniftherequiredXMLdocumentisn'tfound
*
@see#refreshBeanFactory
*
@see#getConfigLocations
*
@see#getResources
*
@see#getResourcePatternResolver
*/
//读取配置文件
protectedvoidloadBeanDefinitions(XmlBeanDefinitionReaderreader)throwsBeansException,IOException{
String[]configLocations
=getConfigLocations();
if(configLocations!=null){
for(inti=0;i<configLocations.length;i++){
reader.loadBeanDefinitions(configLocations[i]);
}
}
}


/**
*Thedefaultlocationfortherootcontextis"/WEB-INF/applicationContext.xml",
*and"/WEB-INF/test-servlet.xml"foracontextwiththenamespace"test-servlet"
*(likeforaDispatcherServletinstancewiththeservlet-name"test").

*/
//获得默认的ConfigLocations
protectedString[]getDefaultConfigLocations(){
if(getNamespace()!=null){
returnnewString[]{DEFAULT_CONFIG_LOCATION_PREFIX+getNamespace()+

DEFAULT_CONFIG_LOCATION_SUFFIX};
}

else{
returnnewString[]{DEFAULT_CONFIG_LOCATION};
}
}



==>AbstractBeanDefinitionReader.loadBeanDefinitions()


代码

publicintloadBeanDefinitions(Stringlocation)throwsBeanDefinitionStoreException{
ResourceLoaderresourceLoader
=getResourceLoader();
if(resourceLoader==null){
thrownewBeanDefinitionStoreException(
"Cannotimportbeandefinitionsfromlocation["+location+"]:noResourceLoaderavailable");
}


if(resourceLoaderinstanceofResourcePatternResolver){
//Resourcepatternmatchingavailable.
try{
//根据配置文件读取相应配置
Resource[]resources=((ResourcePatternResolver)resourceLoader).getResources(location);
intloadCount=loadBeanDefinitions(resources);
if(logger.isDebugEnabled()){
logger.debug(
"Loaded"+loadCount+"beandefinitionsfromlocationpattern["+location+"]");
}

returnloadCount;
}

catch(IOExceptionex){
thrownewBeanDefinitionStoreException(
"Couldnotresolvebeandefinitionresourcepattern["+location+"]",ex);
}
}

else{
//CanonlyloadsingleresourcesbyabsoluteURL.
Resourceresource=resourceLoader.getResource(location);
intloadCount=loadBeanDefinitions(resource);
if(logger.isDebugEnabled()){
logger.debug(
"Loaded"+loadCount+"beandefinitionsfromlocation["+location+"]");
}

returnloadCount;
}
}


这个是其中一个ResourceLoader的实现

==>PathMatchingResourcePatternResolver.getResources(StringlocationPattern);


代码

publicResource[]getResources(StringlocationPattern)throwsIOException{
Assert.notNull(locationPattern,
"Locationpatternmustnotbenull");
if(locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)){
//aclasspathresource(multipleresourcesforsamenamepossible)

if(getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))){
//aclasspathresourcepattern
returnfindPathMatchingResources(locationPattern);
}

else{
//allclasspathresourceswiththegivenname
returnfindAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}

else{
//Onlylookforapatternafteraprefixhere
//(tonotgetfooledbyapatternsymbolinastrangeprefix).
intprefixEnd=locationPattern.indexOf(":")+1;
if(getPathMatcher().isPattern(locationPattern.substring(prefixEnd))){
//afilepattern
returnfindPathMatchingResources(locationPattern);
}

else{
//asingleresourcewiththegivenname
returnnewResource[]{getResourceLoader().getResource(locationPattern)};
}
}
}



==>PathMatchingResourcePatternResolver.findPathMatchingResources(StringlocationPattern);


代码

protectedResource[]findPathMatchingResources(StringlocationPattern)throwsIOException{
StringrootDirPath
=determineRootDir(locationPattern);
StringsubPattern
=locationPattern.substring(rootDirPath.length());
Resource[]rootDirResources
=getResources(rootDirPath);
//collectionFactory初始化一个set容量为16
Setresult=CollectionFactory.createLinkedSetIfPossible(16);
for(inti=0;i<rootDirResources.length;i++){
ResourcerootDirResource
=rootDirResources[i];
if(isJarResource(rootDirResource)){
result.addAll(doFindPathMatchingJarResources(rootDirResource,subPattern));
}

else{
result.addAll(doFindPathMatchingFileResources(rootDirResource,subPattern));
}
}

if(logger.isDebugEnabled()){
logger.debug(
"Resolvedlocationpattern["+locationPattern+"]toresources"+result);
}

return(Resource[])result.toArray(newResource[result.size()]);
}


前面说到有一个刷新WebApplicationContext的操作,但是XmlWebApplicationContext并没有实现refresh方法,而方法的实现写在

AbstractRefreshableWebApplicationContext中


==>AbstractRefreshableWebApplicationContext.refresh();


代码

publicvoidrefresh()throwsBeansException{
if(ObjectUtils.isEmpty(getConfigLocations())){
//设置configLocations为默认的getDefaultConfigLocations()
setConfigLocations(getDefaultConfigLocations());
}

super.refresh();
}



==>AbstractApplicationContext.refresh();


代码

publicvoidrefresh()throwsBeansException,IllegalStateException{
synchronized(this.startupShutdownMonitor){
this.startupTime=System.currentTimeMillis();

synchronized(this.activeMonitor){
this.active=true;
}


//Tellsubclasstorefreshtheinternalbeanfactory.
refreshBeanFactory();
ConfigurableListableBeanFactorybeanFactory
=getBeanFactory();

//Telltheinternalbeanfactorytousethecontext'sclassloader.
beanFactory.setBeanClassLoader(getClassLoader());

//Populatethebeanfactorywithcontext-specificresourceeditors.
beanFactory.addPropertyEditorRegistrar(newResourceEditorRegistrar(this));

//Configurethebeanfactorywithcontextsemantics.
beanFactory.addBeanPostProcessor(newApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.
class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.
class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.
class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.
class);

//Allowspost-processingofthebeanfactoryincontextsubclasses.
postProcessBeanFactory(beanFactory);

//Invokefactoryprocessorsregisteredwiththecontextinstance.
for(Iteratorit=getBeanFactoryPostProcessors().iterator();it.hasNext();){
BeanFactoryPostProcessorfactoryProcessor
=(BeanFactoryPostProcessor)it.next();
factoryProcessor.postProcessBeanFactory(beanFactory);
}


if(logger.isInfoEnabled()){
if(getBeanDefinitionCount()==0){
logger.info(
"Nobeansdefinedinapplicationcontext["+getDisplayName()+"]");
}

else{
logger.info(getBeanDefinitionCount()
+"beansdefinedinapplicationcontext["+

getDisplayName()+"]");
}
}


try{
//Invokefactoryprocessorsregisteredasbeansinthecontext.
invokeBeanFactoryPostProcessors();

//Registerbeanprocessorsthatinterceptbeancreation.
registerBeanPostProcessors();

//Initializemessagesourceforthiscontext.
initMessageSource();

//Initializeeventmulticasterforthiscontext.
initApplicationEventMulticaster();

//Initializeotherspecialbeansinspecificcontextsubclasses.
onRefresh();

//Checkforlistenerbeansandregisterthem.
registerListeners();

//Instantiatesingletonsthislatetoallowthemtoaccessthemessagesource.
beanFactory.preInstantiateSingletons();

//Laststep:publishcorrespondingevent.
publishEvent(newContextRefreshedEvent(this));
}


catch(BeansExceptionex){
//Destroyalreadycreatedsingletonstoavoiddanglingresources.
beanFactory.destroySingletons();
throwex;
}
}
}