spring源代码解析四.docx
《spring源代码解析四.docx》由会员分享,可在线阅读,更多相关《spring源代码解析四.docx(45页珍藏版)》请在冰豆网上搜索。
spring源代码解析四
Spring源代码解析(四):
SpringMVC
2009-08-11(周二)10:
54SpringSpring⁄被围观一共有792个打酱油的路过+下面我们对SpringMVC框架代码进行分析,对于webApplicationContext的相关分析可以参见以前的文档,我们这里着重分析SpringWebMVC框架的实现.我们从分析DispatcherServlet入手:
如转载请注明,转载自:
关注Java[]
本文链接:
-
-
Java代码
//这里是对DispatcherServlet的初始化方法,根据名字我们很方面的看到对各个SpringMVC主要元素的初始化
protectedvoidinitFrameworkServlet()throwsServletException,BeansException{
initMultipartResolver();
initLocaleResolver();
initThemeResolver();
initHandlerMappings();
initHandlerAdapters();
initHandlerExceptionResolvers();
initRequestToViewNameTranslator();
initViewResolvers();
}
//这里是对DispatcherServlet的初始化方法,根据名字我们很方面的看到对各个SpringMVC主要元素的初始化
protectedvoidinitFrameworkServlet()throwsServletException,BeansException{
initMultipartResolver();
initLocaleResolver();
initThemeResolver();
initHandlerMappings();
initHandlerAdapters();
initHandlerExceptionResolvers();
initRequestToViewNameTranslator();
initViewResolvers();
}
看到注解我们知道,这是DispatcherSerlvet的初始化过程,它是在WebApplicationContext已经存在的情况下进行的,也就意味着在初始化它的时候,IOC容器应该已经工作了,这也是我们在web.xml中配置Spring的时候,需要把DispatcherServlet的load-on-startup的属性配置为2的原因。
对于具体的初始化过程,很容易理解,我们拿initHandlerMappings()来看看:
Java代码
privatevoidinitHandlerMappings()throwsBeansException{
if(this.detectAllHandlerMappings){
//这里找到所有在上下文中定义的HandlerMapping,同时把他们排序
//因为在同一个上下文中可以有不止一个handlerMapping,所以我们把他们都载入到一个链里进行维护和管理
MapmatchingBeans=BeanFactoryUtils.beansOfTypeIncludingAncestors(
getWebApplicationContext(),HandlerMapping.class,true,false);
if(!
matchingBeans.isEmpty()){
this.handlerMappings=newArrayList(matchingBeans.values());
//这里通过order属性来对handlerMapping来在list中排序
Collections.sort(this.handlerMappings,newOrderComparator());
}
}
else{
try{
Objecthm=getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME,HandlerMapping.class);
this.handlerMappings=Collections.singletonList(hm);
}
catch(NoSuchBeanDefinitionExceptionex){
//Ignore,we'lladdadefaultHandlerMappinglater.
}
}
//如果在上下文中没有定义的话,那么我们使用默认的BeanNameUrlHandlerMapping
if(this.handlerMappings==null){
this.handlerMappings=getDefaultStrategies(HandlerMapping.class);
……..
}
}
privatevoidinitHandlerMappings()throwsBeansException{
if(this.detectAllHandlerMappings){
//这里找到所有在上下文中定义的HandlerMapping,同时把他们排序
//因为在同一个上下文中可以有不止一个handlerMapping,所以我们把他们都载入到一个链里进行维护和管理
MapmatchingBeans=BeanFactoryUtils.beansOfTypeIncludingAncestors(
getWebApplicationContext(),HandlerMapping.class,true,false);
if(!
matchingBeans.isEmpty()){
this.handlerMappings=newArrayList(matchingBeans.values());
//这里通过order属性来对handlerMapping来在list中排序
Collections.sort(this.handlerMappings,newOrderComparator());
}
}
else{
try{
Objecthm=getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME,HandlerMapping.class);
this.handlerMappings=Collections.singletonList(hm);
}
catch(NoSuchBeanDefinitionExceptionex){
//Ignore,we'lladdadefaultHandlerMappinglater.
}
}
//如果在上下文中没有定义的话,那么我们使用默认的BeanNameUrlHandlerMapping
if(this.handlerMappings==null){
this.handlerMappings=getDefaultStrategies(HandlerMapping.class);
........
}
}
怎样获得上下文环境,可以参见我们前面的对IOC容器在web环境中加载的分析。
DispatcherServlet把定义了的所有HandlerMapping都加载了放在一个List里待以后进行使用,这个链的每一个元素都是一个handlerMapping的配置,而一般每一个handlerMapping可以持有一系列从URL请求到SpringController的映射,比如SimpleUrl
HandlerMaaping中就定义了一个map来持有这一系列的映射关系。
DisptcherServlet通过HandlerMapping使得Web应用程序确定一个执行路径,就像我们在HanderMapping中看到的那样,HandlerMapping只是一个借口:
Java代码
publicinterfaceHandlerMapping{
publicstaticfinalStringPATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE=
Conventions.getQualifiedAttributeName(HandlerMapping.class,"pathWithinHandlerMapping");
//实际上维护一个HandlerExecutionChain,这是典型的Command的模式的使用,这个执行链里面维护handler和拦截器
HandlerExecutionChaingetHandler(HttpServletRequestrequest)throwsException;
}
publicinterfaceHandlerMapping{
publicstaticfinalStringPATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE=
Conventions.getQualifiedAttributeName(HandlerMapping.class,"pathWithinHandlerMapping");
//实际上维护一个HandlerExecutionChain,这是典型的Command的模式的使用,这个执行链里面维护handler和拦截器
HandlerExecutionChaingetHandler(HttpServletRequestrequest)throwsException;
}
他的具体实现只需要实现一个接口方法,而这个接口方法返回的是一个HandlerExecutionChain,实际上就是一个执行链,就像在Command模式描述的那样,这个类很简单,就是一个持有一个Interceptor链和一个Controller:
Java代码
publicclassHandlerExecutionChain{
privateObjecthandler;
privateHandlerInterceptor[]interceptors;
……..
}
publicclassHandlerExecutionChain{
privateObjecthandler;
privateHandlerInterceptor[]interceptors;
........
}
而这些Handler和Interceptor需要我们定义HandlerMapping的时候配置好,比如对具体的SimpleURLHandlerMapping,他要做的就是根据URL映射的方式注册Handler和Interceptor,自己维护一个放映映射的handlerMap,当需要匹配Http请求的时候需要使用这个表里的信息来得到执行链。
这个注册的过程在IOC容器初始化SimpleUrlHandlerMapping的时候就被完成了,这样以后的解析才可以用到map里的映射信息,这里的信息和bean文件的信息是等价的,下面是具体的注册过程:
Java代码
protectedvoidregisterHandlers(MapurlMap)throwsBeansException{
if(urlMap.isEmpty()){
logger.warn("Neither'urlMap'nor'mappings'setonSimpleUrlHandlerMapping");
}
else{
//这里迭代在SimpleUrlHandlerMapping中定义的所有映射元素
Iteratorit=urlMap.keySet().iterator();
while(it.hasNext()){
//这里取得配置的url
Stringurl=(String)it.next();
//这里根据url在bean定义中取得对应的handler
Objecthandler=urlMap.get(url);
//Prependwithslashifnotalreadypresent.
if(!
url.startsWith("/")){
url="/"+url;
}
//这里调用AbstractHandlerMapping中的注册过程
registerHandler(url,handler);
}
}
}
protectedvoidregisterHandlers(MapurlMap)throwsBeansException{
if(urlMap.isEmpty()){
logger.warn("Neither'urlMap'nor'mappings'setonSimpleUrlHandlerMapping");
}
else{
//这里迭代在SimpleUrlHandlerMapping中定义的所有映射元素
Iteratorit=urlMap.keySet().iterator();
while(it.hasNext()){
//这里取得配置的url
Stringurl=(String)it.next();
//这里根据url在bean定义中取得对应的handler
Objecthandler=urlMap.get(url);
//Prependwithslashifnotalreadypresent.
if(!
url.startsWith("/")){
url="/"+url;
}
//这里调用AbstractHandlerMapping中的注册过程
registerHandler(url,handler);
}
}
}
在AbstractMappingHandler中的注册代码:
Java代码
protectedvoidregisterHandler(StringurlPath,Objecthandler)throwsBeansException,IllegalStateException{
//试图从handlerMap中取handler,看看是否已经存在同样的Url映射关系
ObjectmappedHandler=this.handlerMap.get(urlPath);
if(mappedHandler!
=null){
……..
}
//如果是直接用bean名做映射那就直接从容器中取handler
if(!
this.lazyInitHandlers&&handlerinstanceofString){
StringhandlerName=(String)handler;
if(getApplicationContext().isSingleton(handlerName)){
handler=getApplicationContext().getBean(handlerName);
}
}
//或者使用默认的handler.
if(urlPath.equals("/*")){
setDefaultHandler(handler);
}
else{
//把url和handler的对应关系放到handlerMap中去
this.handlerMap.put(urlPath,handler);
……..
}
}
protectedvoidregisterHandler(StringurlPath,Objecthandler)throwsBeansException,IllegalStateException{
//试图从handlerMap中取handler,看看是否已经存在同样的Url映射关系
ObjectmappedHandler=this.handlerMap.get(urlPath);
if(mappedHandler!
=null){
........
}
//如果是直接用bean名做映射那就直接从容器中取handler
if(!
this.lazyInitHandlers&&handlerinstanceofString){
StringhandlerName=(String)handler;
if(getApplicationContext().isSingleton(handlerName)){
handler=getApplicationContext().getBean(handlerName);
}
}
//或者使用默认的handler.
if(urlPath.equals("/*")){
setDefaultHandler(handler);
}
else{
//把url和handler的对应关系放到handlerMap中去
this.handlerMap.put(urlPath,handler);
........
}
}
handlerMap是持有的一个HashMap,里面就保存了具体的映射信息:
Java代码
privatefinalMaphandlerMap=newHashMap();
privatefinalMaphandlerMap=newHashMap();
而SimpleUrlHandlerMapping对接口HandlerMapping的实现是这样的,这个getHandler根据在初始化的时候就得到的映射表来生成DispatcherServlet需要的执行链
Java代码
publicfinalHandlerExecutionChaingetHandler(HttpServletRequestrequest)throwsException{
//这里根据request中的参数得到其对应的handler,具体处理在AbstractUrlHandlerMapping中
Objecthandler=getHandlerInternal(request);
//如果找不到对应的,就使用缺省的handler
if(handler==null){
handler=this.defaultHandler;
}
//如果缺省的也没有,那就没办法了
if(handler==null){
returnnull;
}
//如果handler不是一个具体的handler,那我们还要到上下文中取
if(handlerinstanceofString){
StringhandlerName=(String)handler;
handler=getApplicationContext().getBean(handlerName);
}
//生成一个HandlerExecutionChain,其中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一个拦截器组。
returnnewHandlerExecutionChain(handler,this.adaptedInterceptors);
}
publicfinalHandlerExecutionChaingetHandler(HttpServletRequestrequest)throwsException{
//这里根据request中的参数得到其对应的handler,具体处理在AbstractUrlHandlerMapping中
Objecthandler=getHandlerInternal(request);
//如果找不到对应的,就使用缺省的handler
if(handler==null){
handler=this.defaultHandler;
}
//如果缺省的也没有,那就没办法了
if(handler==null){
returnnull;
}
//如果handler不是一个具体的handler,那我们还要到上下文中取
if(handlerinstanceofString){
StringhandlerName=(String)handler;
handler=getApplicationContext().getBean(handlerName);
}
//生成一个HandlerExecutionChain,其中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一个拦截器组。
returnnewHandlerExecutionChain(handler,this.adaptedInterceptors);
}
我们看看具体的handler查找过程:
Java代码
protectedObjectgetHandlerInternal(HttpServletRequestrequest)throwsException{
//这里的HTTPRequest传进来的参数进行分析,得到具体的路径信息。
StringlookupPath=this.urlPathHelper.getLookupPathForRequest(request);
…….//下面是根据请求信息的查找
returnlookupHandler(lookupPath,request);
}
protectedObjectlookupHandler(StringurlPath,HttpServletRequestrequest){
//如果能够直接能在SimpleUrlHandlerMapping的映射表中找到,那最好。
Objecthandler=