springmvc源码分析
A. 如何深入理解springmvc
许多 ASP.NET 开发人员开始接触 MVC,都认为 MVC 与 ASP.NET 完全没有关系,是一个全新的 Web 开发。
事实上 ASP.NET 是创建 WEB 应用的框架,而 MVC 是一种能够用更好的方法来组织并管理代码的体系,所以可以称之为 ASP.NET MVC。
因此,我们可以将原来的 ASP.NET 称为 ASP.NET Webforms,新的 MVC 称为 ASP.NET MVC。
深入理解,请参考下面的博客
http://gcdn.gcpowertools.com.cn/showtopic-23645-1-3.html
B. spring mvc后台框架源码
1. 模块化、服务化,流程化,耦合度低、扩展性好,灵活度高,工具类封装完整,干净利索,调用简单方便
2. 提供Rest服务,支持APP手机应用(android和ios)接口、php、.net、易语言、VB等第三方接口调用
3. 全新高大尚HTML5+css3.0+bootstrap响应式开发界面UI,( 手机 PC 平板 截图在下面)、前沿. spring restful 风格
4. 框架搭建完善成熟,在此基础上做过很多项目,系统具有并发处理、分布式、稳定性。
5. 系统功能完善,此为框架平台,文档、注释齐全,提供技术支持,专门供二次开发
6. 在此基础上可二次开发(OA、ERP、CRM ,医疗管理、金融、网站后台、APP后台、电子商务、商城(赠送UI)等等
C. 如何学习springmvc源代码
首先要了解设计模式,这个是阅读大师源码的一个桥梁,很多代码看上去很多,其实就是一种模式。了解了模式后,整个关系图就清楚了。
还有善于分片阅读,找简单的读,可以先读spring jdbc,这部分的模板跟回调看起来会简单点。
然后再看IOC,看IOC之前必须对spring IOC原理掌握的很透彻,怎么扩展,怎么写胶水代码整合其他框架。建议熟读Spring-Reference。
然后再读源码,先学习怎么写出漂亮的代码,再学习怎么设计出漂亮的模式。
D. 如何读懂spring mvc 源码
读顺序:
1. SpringMVC入门
SpringMVC的入门文章, 对于某些没接触过SpringMVC的同学来说,可以阅读以下,了解这个框架的结构以及使用,以入门的同学可以选择不看~
2. SpringMVC核心分发器DispatcherServlet分析
SpringMVC入口Servlet -> DispatcherServlet的分析,解释了DispatcherServlet的父类FrameworkServlet以及FrameworkServlet的父类HttpServletBean的作用
3. 详解SpringMVC请求的时候是如何找到正确的Controller
E. 《看透SpringMVC源代码分析与实践》epub下载在线阅读全文,求百度网盘云资源
《看透SpringMVC源代码分析与实践》(韩路彪)电子书网盘下载免费在线阅读
链接: https://pan..com/s/1ke0ymgIdAwC85IhD0uUG_Q
书名:看透SpringMVC源代码分析与实践
作者:韩路彪
出版社:机械工业出版社
副标题:源代码分析与实践
原作名:韩路彪
出版年:2016-1-1
页数:309
内容简介
国内资深Web开发专家根据Spring MVC全新技术撰写,基于实际生产环境,从基础知识、源代码和实战3个维度对Spring MVC的结构和实现进行详细讲解
全面介绍Spring MVC的架构、原理、核心概念和操作,通过案例完整呈现Tomcat的实现,系统总结Spring MVC九大组件的处理以及常用的技巧和实践
在大型网站和复杂系统的开发中,java具有天然的优势,而在Java的Web框架中Spring MVC以其强大的功能以及简单且灵活的用法受到越来越多开发者的青睐。本书不仅详细地分析Spring MVC的结构及其实现细节,而且讲解网站的不同架构及其演变的过程,以及网络底层协议的概念及其实现方法,帮助读者开发更高效的网站。
作者简介
韩路彪当代知名作家。
F. 如何深入 spring mvc
SpringMVC是一个轻量级的MVC框架,SpringMVC由于其轻量级的实现以及与Spring框架的无缝整合等诸多优势,近年来在MVC框架中脱颖而出,受到诸多开发人员的青睐,学习SpringMVC势在必行。
Web环境中使用SpringMVC:SpringMVC提供了可插拔式的框架嵌入形式,将SpirngMVC插入或者从Web项目中卸载只需要简单的修改配置文件即可。
配置前端控制器,SpringMVC的入口程序为一个全局的Servlet,该Servlet拦截指定的一组请求交给SpringMVC框架执行后续的处理操作,在Web.xml中配置如下字段。
<!--SpingMVC的前端控制器-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置SpringMVC的IOC容器-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!--配置拦截所有的请求-->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping></span></span>
创建SpringMVC IOC容器的配置文件root-context.xml并定义视图解析器,位置/WEB-INF/
<!--配置自动扫面的包-->
<context:component-scanbase-package="cn.com.xiaofen"/>
<!--定义视图解析器-->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="prefix"value="/WEB-INF/view/"></property>
<propertyname="suffix"value=".jsp"></property>
</bean>
<!--<mvc:default-servlet-handler/><mvc:annotation-driven/>--></span></span>
定义控制器,SpringMVC中定义方法来响应客户端请求,内存开销更小效率更高。
@Controller
@RequestMapping("/T")
publicclassT{
@RequestMapping("/t_1")
publicStringt_1(){
System.out.println("t_1");
return"index";
}
}
定义视图,根据实际的视图解析器完成相关视图的配置,当前配置视图应该在/WEB-INF/view/下且文件类型为JSP文件,具体的应该在该目录下新建一个名称为index的jsp文件名称。
[java]view plain
[java]view plain
[java]view plain
SpringMVC处理请求的工作流:DispatcherServlet作为SpringMVC框架的入口程序,负责调度SpringMVC框架响应用户的请求,如下图为宏观上SpingMVC处理一次请求大概需要经过以下调度过程。
请求进入由前端控制器(DispatcherServlet )拦截。
前端控制器分析请求将请求委托至具体的控制器来处理。
控制器处理请求返回逻辑视图(Model)。
前端控制器得到逻辑视图对象,调度视图解析器,解析视图模版给用户响应。
返回前端控制器。
DispatcherServlet调用doDispatch处理请求。
try{
/*逻辑视图及上文提到的Model*/
ModelAndViewmv=null;
ExceptiondispatchException=null;
try{
/*文件上传预处理*/
processedRequest=checkMultipart(request);
multipartRequestParsed=(processedRequest!=request);
/*确定当前请求的处理者*/
mappedHandler=getHandler(processedRequest);
/*请求资源未发现*/
if(mappedHandler==null||mappedHandler.getHandler()==null){
noHandlerFound(processedRequest,response);
return;
}
/*确定当前请求的处理者适配器*/
HandlerAdapterha=getHandlerAdapter(mappedHandler.getHandler());
//...............
/*请求调度前应用的拦截器*/
if(!mappedHandler.applyPreHandle(processedRequest,response)){
return;
}
/*调用处理程序*/
mv=ha.handle(processedRequest,response,mappedHandler.getHandler());
//......
/*请求调度后应用的拦截器*/
mappedHandler.applyPostHandle(processedRequest,response,mv);
}
catch(Exceptionex){
dispatchException=ex;
}
/*解析视图给用户响应*/
processDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException);
}
理解HandlerMapper,一个HandlerMapper代表一个请求到到处理对象的映射,该对象的创建依据是请求响应关系。getHandler方法部分源码分析如下。
(HttpServletRequestrequest)throwsException{
遍历查找满足条件的HandlerMapping
for(HandlerMappinghm:this.handlerMappings){
if(logger.isTraceEnabled()){
logger.trace(
"Testinghandlermap["+hm+"]inDispatcherServletwithname'"+getServletName()+"'");
}
HandlerExecutionChainhandler=hm.getHandler(request);
if(handler!=null){
存在
returnhandler;
}
}
不存在
returnnull;
}
理解HandlerAapter,SpringMVC 中通过HandlerAdapter的handler方法来调用实际的处理请求的函数。getHandlerAapter 部分源码如下。
(Objecthandler)throwsServletException{
for(HandlerAdapterha:this.handlerAdapters){
if(logger.isTraceEnabled()){
logger.trace("Testinghandleradapter["+ha+"]");
}
是否支持处理当前的HandlerMapper
if(ha.supports(handler)){
returnha;
}
}
当前的HandlerMapper不能被处理报异常
thrownewServletException("Noadapterforhandler["+handler+
"]:ortsthishandler");
}
Model到视图,SpringMVC 中ModelAndView保存了逻辑视图与真实视图的关系,确定了当前请求为用户返回的View,processDispatchResult 源码分析如下。
(HttpServletRequestrequest,HttpServletResponseresponse,
,ModelAndViewmv,Exceptionexception)throwsException{
booleanerrorView=false;
/*处理异常信息*/
if(exception!=null){
if(){
logger.debug("",exception);
mv=((ModelAndViewDefiningException)exception).getModelAndView();
}
else{
Objecthandler=(mappedHandler!=null?mappedHandler.getHandler():null);
mv=processHandlerException(request,response,handler,exception);
errorView=(mv!=null);
}
}
/*渲染视图,返回响应*/
if(mv!=null&&!mv.wasCleared()){
render(mv,request,response);
if(errorView){
WebUtils.clearErrorRequestAttributes(request);
}
}
else{
if(logger.isDebugEnabled()){
logger.debug("'"+getServletName()+
"':");
}
}
}
SpringMVC请求流程(部分源码分析):由DispatcherServlet的doService()方法入手,篇幅关系,下文仅列出核心的代码,下文的代码并并保证时间上的顺序性。
[java]view plain
[java]view plain
[java]view plain
[java]view plain
G. spring MVC怎么理解
Spring MVC Framework大至流程如下:
当web程序启动的时候,ContextLoaderServlet会把对应的配置文件信息读取出来,通过注射去初始化控制器DispatchServlet. 而当接受到一个HTTP请求的时候, DispatchServlet会让HandlerMapping去处理这个请求.HandlerMapping根据请求URL(不一定非要是URL,完全可以自定义,非常灵活)来选择一个Controller. 然后DispatchServlet会在调用选定的Controller的handlerRequest方法,并且在这个方法前后调用这个Controller的interceptor(假如有配置的话),然后返回一个视图和模型的集合ModelAndView.框架通过ViewResolver来解析视图并且返回一个View对象,最后调用View的render方法返回到客户端
DispatcherServlet
这是框架的控制器,是一个具体类,它通过运行时的上下文对象来初始化.控制器本身并不去控制流程,而只是是Controller的”控制器”,他只是把处理请求的责任委托给了对应的Controller.
控制器继承自抽象基类FrameworkServlet,它的属性webApplicationContext就代表着这个web程序上下文,而这个上下文对象默认实现就是从一个XML文件读取配置信息(当然也可以是其他文件格式). WebApplicationContext其实是beans包的东西,这个包提供了这个Spring整个框架的基础结构,以后我会分析这个包的内容.但是现在仅仅需要知道WebApplicationContext代表一个web应用的上下文对象.
现在来看看DispatchServlet是如何工作的:
DispatchServlet由于继承自抽象基类FrameworkServlet,而FrameworkServlet里的doGet(),doPost()方法里有调用serviceWrapper(),跳到serviceWrapper()里去看,结果发现它有把具体实现委托给了doService(request, response); 方法.所以现在已经很清楚了, DispatchServlet真正实现功能的是doService() 这个方法.
特别的, FrameworkServlet的initFrameworkServlet()这个方法是控制器的初始化方法,用来初始化HandlerMappings之类的对象,这也是延迟到子类实现的.其实就是一个Template模式的实现.don’t call us, we will call u.总的看来,Spring就是通过这样来实现它的控制反转的:用框架来控制流程,而不是用户
跳到doService()一看究竟,就会发现真正工作的又是另一个助手函数doDispatch(request, response),没办法,继续看下去,发现这样两行代码
HandlerExecutionChain mappedHandler = null;
mappedHandler = getHandler(processedRequest, false);
看HandlerExecutionChain源码就发现它其实就是对Controller和它的Interceptors的进行了包装;
getHandler()就是从HandlerMappings(这是一个List,存放的handlerMapping对象)中取出对应的handlerMapping对象, 每个HandlerMapping对象代表一个Controller和URL的映射(其实在运行的时候是一个HandlerExecutionChain和URL的映射,而HandlerExecutionChain对象其实就是对Controller和它interceptors的一个包装器,可以把HandlerMapping看成Controller和URL的映射).而这个HandlerMapping是通过配置文件在运行时注射进来的,一般是SimpleUrlHandlerMapping这个子类
取得了HandlerMapping对象,继续向下看,发现:
if (mappedHandler.getInterceptors() != null) {
for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {
HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
return;
}
interceptorIndex = i;
}
}
这里就是在调用Controller的拦截器,原理就是这句了:
interceptor.preHandle(processedRequest, response, mappedHandler.getHandler(), mv);
preHandle方法传入了mappedHandler.getHandler()这个参数来实现递归调用!而interceptor.postHandle方法如此一般.只不过这个方法是在handleRequest方法后调用
继续看下去:
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
发现Controller的handleRequest真正的操作又被代理给了HandlerAdapter的handle方法,并且返回一个ModelAndView,我想这里增加一层的意义应该是为了解除Controller和DispatchServlet的耦合吧.
接着就很简单了,调用render()方法,在这个方法里面由ViewResoler解析出视图名,再调用视图对象的render方法把合适的视图展现给用户
到此,控制器的流程就OVER了
HandlerMapping
通过使用HandlerMapping,控制器可以用URL和某一个Controller进行标准的映射,而实现URL映射的具体子类的UrlHandlerMapping.
Spring还允许我们自定义映射,比如通过Session,cookie或者用户状态来映射.而这一切仅仅只需要实现HandlerMapping接口而已.不过URL映射已经能满足大部分的要求
Controller
Controller 类似Structs的Action, Controller接口只有一个方法handleRequest(),放回一个ModelAndView对象,如同设计目标所说的那样,每个Controller都是一个java组件,所以它可以在上下文环境中任意配置,组件属性都会在初始化的时候被配置.Spring自己提供了几个具体的实现.方便我们使用
ViewResolver
Controller通常返回包含视图名字而不是视图对象的ModelAndView对象.从而彻底的解除了控制器和视图之间的耦合关系,并且在这里还可以提供国际化的支持.
在你的配置文件中你可以:
welcomeView.class = org.springframework.web.servlet.view. InternalResourceView
welcomeView.url=/welcome.jsp
也可以
welcomeView.class = org.springframework.web.servlet.view.xslt. XsltView
welcomeView.url=/xslt/default.xslt
View
这也是一个java组件,它不做任何请求处理或是业务逻辑,它仅仅获取模型传递的数据,并把数据显示出来.它里面的 render方法按照如下流程工作:
l 设置模型的数据到request作用域
l 取得视图的URL
l 转发到对应的URL
H. 如何学习springmvc源码 csdn
善于利用时间:时间是有限的,知识是无限的,我们不可能在有限的时间里学会无限的知识,所以我们必须有选择重点进行学习。所谓重点一个是薄弱的科目,二是各科的重点知识,利用有限时间针对性的进行学习能够大大提高学习效率
I. 看透springmvc源代码分析与实践 怎么样
Tomcat 里的Server由org.apache.catalina.startup.Catalina来管理
,Catalina是整个Tomcat的管理类,它里面的三个方法load,start,stop分别用来管理整个服务器的生命周期,load方法用于根据conf/server.xml文件创建Server并调用
Server的init方法进行初始化,start
方法用于启动服务器,stop方法用于停止服务器,start和stop方法在内部分别调用了Server的start
和stop方法,load方法内部调用了Server的init方法,这三个方法都
会按容器的结构逐层调用相应的方法,比如,Server的start方法中会调用
所有的Service中的start方法,Service中的start方法又会调用所包含的connectors和container的start方法,这样整个服务器就启动了,init和stop方法也一样,这就是tomcat生命周期的管理方式。
Catalina中还有个await方法很重要,此方法直接调用 了Server的await方法,这个方法的作用是进入一个循环,让主线程不会退出。
Tomcat的入口org.apache.catalina.startup.Bootstrap.main(),
Bootstrap的作用类似一个CatalinaAdaptor,具体过程还是使用Catalina来完成,这么做的好处是可以把启动的入口和具体的管理类分开,这样可以就可以方便创建出多种启动方式 ,每种启动方式只需要写一个相应的CatalinaAdaptor就可以了。
Bootstrap是Tomcat的入口,正常情况下启动Tomcat就是调用的Bootstrap的main方法,其代码如下:
// org.apache.catalina.startup.Bootstrap
public static void main(String args[]) {
// 先新建一个Bootstrap
if (daemon == null) {
Bootstrap bootstrap = new Bootstrap();
try {
//初始化了ClassLoader,并用ClassLoader创建了Catalina实例,赋给catalinaDaemon变量
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
try {
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);
daemon.start();
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null==daemon.getServer()) {
System.exit(1);
}
System.exit(0);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
} catch (Throwable t) {
if (t instanceof InvocationTargetException &&
t.getCause() != null) {
t = t.getCause();
}
handleThrowable(t);
t.printStackTrace();
System.exit(1);
}
}
可以看到这里的main非常简单,只有两部分内容:首先新建了Bootstrap,并执行init方法初始化;然后处理main方法传入的命令,如果args参数为空,默认执行start。
在init方法里初始化了ClassLoader,并用ClassLoader创建了Catalina实例,然后赋给catalinaDaemon变量,后面对命令的操作都要使用catalinaDaemon来具体执行。
对start命令的处理调用了三个方法:setAwait(true)、load(args)和start()。这三个方法内部都调用了Catalina的相应方法进行具体执行,只不过是用反射来调用的。start方法(另外两个方法会处理一些参数,调用方法类似)的代码如下:
// org.apache.catalina.startup.Bootstrap
public void start()
throws Exception {
if( catalinaDaemon==null ) init();
Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
method.invoke(catalinaDaemon, (Object [])null);
}
这里首先判断catalinaDaemon有没有初始化,如果没有则调用init方法对其进行初始化,然后使用Method进行反射调用Catalina的start方法。Method是java.lang.reflect包里的
类,代表一个具体的方法,可以使用其中的invoke方法来执行所代表的方法,invoke方法有两个参数,第一参数是Method方法所在的实体,第二个参数是可变参数用于Method方法执行时所需要的参数,所以上面的调用相当于((Catalina)catalinaDaemon).start()。setAwait和load也用类似的方法调用了Catalina中的setAwait和load方法。
7.1.3Catalina的启动过程
从前面的内容可以知道,Catalina的启动主要是调用setAwait、load和start方法来完成的。setAwait方法用于设置Server启动完成后是否进入等待状态的标志,如果为true则进入,否则不进入;load方法用于加载配置文件,创建并初始化Server;start方法用于启动服务器。下面分别来看一下这三个方法。
首先来看setAwait方法,代码如下:
// org.apache.catalina.startup.Catalina
public void setAwait(boolean b) {
await = b;
}
这个方法非常简单,就是设置await属性的值,await属性会在start方法中的服务器启动完之后使用它来判断是否进入等待状态。
Catalina的load方法根据conf/server.xml创建了Server对象,并赋值给server属性(具体解析操作是通过开源项目Digester完成的),然后调用了server的init方法,代码如下:
// org.apache.catalina.startup.Catalina
public void load() {
long t1 = System.nanoTime();
// 省略创建 server代码,创建过程使用Digester完成
try {
getServer().init();
} catch (LifecycleException e) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new java.lang.Error(e);
} else {
log.error("Catalina.start", e);
}
}
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
//启动过程中,控制台可以看到
log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
}
}
Catalina的start方法主要调用了server的start方法启动服务器,并根据await属性判断是否让程序进入了等待状态,代码如下:
//org.apache.catalina.startup.Catalina
public void start() {
if (getServer() == null) {
load();
}
long t1 = System.nanoTime();
try {
// 调用Server的start方法启动服务器
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
}
// 此处省略了注册关闭钩子代码
// 进入等待状态
if (await) {
await();
stop();
}
}
这里首先判断Server是否已经存在了,如果不存在则调用load方法来初始化Server,然后调用Server的start方法来启动服务器,最后注册了关闭钩子并根据await属性判断是否进入等待状态,之前我们已将这里的await属性设置为true了,所以需要进入等待状态。进入等待状态会调用await和stop两个方法,await方法直接调用了Server的await方法,Server的await方法内部会执行一个while循环,这样程序就停到了await方法,当await方法里的while循环退出时,就会执行stop方法,从而关闭服务器。
7.1.4Server的启动过程
Server接口中提供addService(Service service)、removeService(Service
service)来添加和删除Service,Server的init方法和start方法分别循环调用了每个Service的init方法和start方法来启动所有Service。
Server的默认实现是org.apache.catalina.core.StandardServer,StandardServer继承自Lifecycle-MBeanBase,LifecycleMBeanBase又继承自LifecycleBase,init和start方法就定义在了LifecycleBase中,LifecycleBase里的init方法和start方法又调用initInternal方法和startInternal方法,这两个方法都是模板方法,由子类具体实现,所以调用StandardServer的init和start方法时会执行StandardServer自己的initInternal和startInternal方法,这就是Tomcat生命周期的管理方式,更详细的过程见7.2节。StandardServer中的initInternal和startInternal方法分别循环调用了每一个service的start和init方法,代码如下:
//org.apache.catalina.core.StandardServer
protected void startInternal() throws LifecycleException {
……
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
protected void initInternal() throws LifecycleException {
……
for (int i = 0; i < services.length; i++) {
services[i].init();
}
}
除了startInternal和initInternal方法,StandardServer中还实现了await方法,Catalina中就是调用它让服务器进入等待状态的,其核心代码如下:
//org.apache.catalina.core.StandardServer
public void await() {
// 如果端口为-2则不进入循环,直接返回
if( port == -2 ) {
J. springmvc中的requestmapping注解怎么实现的
使用@RequestMapping注解时,配置的信息最后都设置到了RequestMappingInfo中.
RequestMappingInfo封装了PatternsRequestCondition,,ParamsRequestCondition等,所以自己不干活,所有的活都是委托给具体的condition处理.
先看下封装的RequestCondition吧,之前的文章将的比较细了,不清楚各个类具体是做什么的,可以移步这里<SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系>
1 package org.springframework.web.servlet.mvc.method;
2 public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
3
4 private final PatternsRequestCondition patternsCondition;
5
6 private final methodsCondition;
7
8 private final ParamsRequestCondition paramsCondition;
9
10 private final HeadersRequestCondition headersCondition;
11
12 private final ConsumesRequestCondition consumesCondition;
13
14 private final ProcesRequestCondition procesCondition;
15
16 private final RequestConditionHolder customConditionHolder;
17 }
初始化没什么好看的,直接看接口的实现吧.
貌似combine也没啥料,就是分别委托
1 /**
2 * Combines "this" request mapping info (i.e. the current instance) with another request mapping info instance.
3 * <p>Example: combine type- and method-level request mappings.
4 * @return a new request mapping info instance; never {@code null}
5 */
6 public RequestMappingInfo combine(RequestMappingInfo other) {
7 PatternsRequestCondition patterns = this.patternsCondition.combine(other.patternsCondition);
8 methods = this.methodsCondition.combine(other.methodsCondition);
9 ParamsRequestCondition params = this.paramsCondition.combine(other.paramsCondition);
10 HeadersRequestCondition headers = this.headersCondition.combine(other.headersCondition);
11 ConsumesRequestCondition consumes = this.consumesCondition.combine(other.consumesCondition);
12 ProcesRequestCondition proces = this.procesCondition.combine(other.procesCondition);
13 RequestConditionHolder custom = this.customConditionHolder.combine(other.customConditionHolder);
14
15 return new RequestMappingInfo(patterns, methods, params, headers, consumes, proces, custom.getCondition());
16 }
getMatchingCondition只是体现出可能基于性能消耗的考虑,把PatternsRequestCondition和RequestConditionHolder的比较放到后面单独处理了.
1 /**
2 * Checks if all conditions in this request mapping info match the provided request and returns
3 * a potentially new request mapping info with conditions tailored to the current request.
4 * <p>For example the returned instance may contain the subset of URL patterns that match to
5 * the current request, sorted with best matching patterns on top.
6 * @return a new instance in case all conditions match; or {@code null} otherwise
7 */
8 public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
9 methods = methodsCondition.getMatchingCondition(request);
10 ParamsRequestCondition params = paramsCondition.getMatchingCondition(request);
11 HeadersRequestCondition headers = headersCondition.getMatchingCondition(request);
12 ConsumesRequestCondition consumes = consumesCondition.getMatchingCondition(request);
13 ProcesRequestCondition proces = procesCondition.getMatchingCondition(request);
14
15 if (methods == null || params == null || headers == null || consumes == null || proces == null) {
16 return null;
17 }
18
19 PatternsRequestCondition patterns = patternsCondition.getMatchingCondition(request);
20 if (patterns == null) {
21 return null;
22 }
23
24 RequestConditionHolder custom = customConditionHolder.getMatchingCondition(request);
25 if (custom == null) {
26 return null;
27 }
28
29 return new RequestMappingInfo(patterns, methods, params, headers, consumes, proces, custom.getCondition());
30 }
compareTo就是排了个不同RequestCondition的优先级
1 /**
2 * Compares "this" info (i.e. the current instance) with another info in the context of a request.
3 * <p>Note: it is assumed both instances have been obtained via
4 * {@link #getMatchingCondition(HttpServletRequest)} to ensure they have conditions with
5 * content relevant to current request.
6 */
7 public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
8 int result = patternsCondition.compareTo(other.getPatternsCondition(), request);
9 if (result != 0) {
10 return result;
11 }
12 result = paramsCondition.compareTo(other.getParamsCondition(), request);
13 if (result != 0) {
14 return result;
15 }
16 result = headersCondition.compareTo(other.getHeadersCondition(), request);
17 if (result != 0) {
18 return result;
19 }
20 result = consumesCondition.compareTo(other.getConsumesCondition(), request);
21 if (result != 0) {
22 return result;
23 }
24 result = procesCondition.compareTo(other.getProcesCondition(), request);
25 if (result != 0) {
26 return result;
27 }
28 result = methodsCondition.compareTo(other.getMethodsCondition(), request);
29 if (result != 0) {
30 return result;
31 }
32 result = customConditionHolder.compareTo(other.customConditionHolder, request);
33 if (result != 0) {
34 return result;
35 }
36 return 0;
37 }