如何在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
代码
#DefaultWebApplicationContextimplementationclassforContextLoader.
#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;
}
}
}
==>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
代码
#DefaultWebApplicationContextimplementationclassforContextLoader.
#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;
}
}
}