周一至周日早九点半!
下午三点半!
佳构技能文章定时送上!


佳构学习资料获取通道,拜会文末

1、回顾servlet 与jsp 实行过程

jspspringmvc循环Java互联网架构spring mvc 道理深度解析 SQL

2、Spring MVC要求处理流程

3,mvc 体系构造详解

URL映射

表单参数映射

调用目标Control

数据模型映射

视图解析

非常处理

DispatcherServlet

DispatcherServlet它的浸染有点儿类似于网关,DispatcherServlet卖力将要求转发到不同的Controller上去。

配置DispatcherServlet

/ 后面不能写成/否则随意马虎出问题。

编写Controller,继续controller类。
实现handlerRequest接口。
指定ModelAndView。
这是一种办法。

第二种办法 继续 HttpRequestHandler类。
那么DispatcherServlet是如何去匹配不同的controller的呢?这就须要理解SpringMVC的体系构造。
全体体系构造都搞懂才行。
下面就从一个全局的视角去看Spring MVC的体系构造。

SpringMVC的体系构造图

DispatcherServlet是通过HandlerMapping的一组映射关系去找到我们的目标Controller

通过上面我们知道Controller存在的形式是多种多样的。
可以通过Controller接口的形式,也可以通过@Controller表明的形式存在。
等等等。


有这么多不同的Controller形式DispatcherServlet是如何去实行的呢?这里面就涉及到一个HandlerAdapter掌握器适配器。
找到数据模型的一个映射。
然后试图解析是通过ViewResolver这个东东。
他支持各种各样的试图解析。
view用于详细的试图解析。
HandlerExceptionResolver非常拦截解析器。

下面就环绕这张图去逐一进行源码剖析。

一,HandlerMapping源码剖析

HandlerMapping是一个接口,他有两个实现类,MatchableHandlerMapping和AbstractHandlerMapping。
HandlerMapping在getHandler里面并没有返回handler(我们的目标实行器,也便是我们的controller)而是返回一个实行链条。
HandlerExecutionChain。

根据下图可知HandlerExecutionChain里面有一个getHandler方法,这里面返回了Handler。
但是详细的是哪个一个Handler是不愿定的,由于他是Object类型的。
以是通过动态代理的办法是不能实现的。
只能通过这个实行链条去返回目标Handler。
后续的文章我们会对实行链条做深入的讲解。

然后看上面的类继续关系图。
左面继续了AbstractUrlHandlerMapping个中AbstractDetectingUrlHandlerMapping起到自动创造的浸染,他是根据Bean的名称,而且是必须以/开头。
比如这样

<bean name=\"大众/hello.do\"大众 class=\"大众com.tuling.control.SimpleControl\"大众/>

然后SimpleUrlHandlerMapping。
如果不须要自动创造功能,则利用这个。
SimpleUrlHandlerMapping是自己配置URL和controller之间的一个关系。
以是他们之间的差异便是一个自动创造,一个手动配置。
AbstractHandlerMethodMapping是对方法进行映射RequestMappingInfoHandlerMapping这个大家比较熟习了,便是通过@RequestMapping进行映射的。
如果配置了SimpleUrlHandlerMapping或者BeanNameUrlHandlerMapping那么默认的就会失落效。
SimpleUrlHandlerMapping和BeanNameUrlHandlerMapping可以同时配置,都可以映射到我们的Controller掌握器。

SimpleUrlHandlerMapping的初始化实行流程

对initApplicationContext()方法进行调用。
个中super.initApplicationContext();这里是初始化一些拦截器
比如自动创造拦截器啊等等等。
this.registerHandlers(this.urlMap);开始进行Url的匹配点进去看一下可知如果urlMap不为空才进行匹配。
第一步是!url.startsWith(\"大众/\公众)如果不是/开头的。
就会把你的URL加上/然后获取Handler,便是我们的掌握器。
然后判断handler是不是String类型的,。
如果是进行去除空格的处理。
然后实行this.registerHandler(url, handler);点进去创造,将handler转化为Object类型。
然后判断是否是

末了如果以上情形都不是,则通过this.handlerMap.put(urlPath, resolvedHandler);将url和handler绑定在一起。
如果说handler是SimpleUrlHandlerMapping的访问实行流程

我们知道终极实行调用的一定是DispatcherServlet。
以是我们从这里开始入手。
找到getHandler

首先通过Iterator var2 =this.handlerMappings.iterator();或取到所有的Mapping然后遍历。
遍历一次取出一个handlerMapping然后调用handlerMapping。
点进去看看。
第一行getHandlerInternal这个方法很主要。
点进去看看,在这个方法里第一行通过getUrlPathHelper().getLookupPathForRequest(request);去解析我们地址栏上的URL。
比如或取到的是/hello.do。
第二行通过Object handler = lookupHandler(lookupPath, request);去查找对应的handler。
点进去创造便是从上面put进去的handlerMap找到对应的handler。
在末了return一个buildPathExposingHandler。
点进去创造HandlerExecutionChain这里面配置了一个拦截器链,那么返回的并不是我们终极的handler。

那么getHandlerInternal方法的第二行也实行完了。
终极拿到得是一个拦截器链,如果说拦截器链为空则判断第一行的url解析器拿到得/hello.do是否即是/如果是Object rawHandler=getRootHandler()设置为根节点的handler,然后判断rawHandler是否即是空,如果是则调用默认的handler。
如果不即是空呢,则直接通过beanName从Spring容器找到Handler。
再调用buildPathExposingHandler。
还是获取一个拦截器链。
终极,将拦截器链返回。
getHandlerInternal方法实行结束。
返回到getHandler方法里。
那么如果说,没有获取到拦截器链,则获取默认的handler。
如果不为空,则直接通过beanName从容器中获取到handler。
然后,去创建一个拦截器链条,又加入了一个拦截器。
最后进一步获取handler。
然后返回HandlerExecutionChain。
末了通过HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());获取到的才是我们的handler。
SimpleUrlHandlerMapping实行流程到此先容完毕,说实话SpringMVC的代码写的跟IOC\aop差着一大块儿的水平觉得。

Controller 接口:

HttpRequestHandler 接口:

HttpServlet 接口:

@RequestMapping方法表明

可以看出 Handler 没有统一的接口,当dispatchServlet获取当对应的Handler之后如何调用呢?调用其哪个方法?这里有两种办理办法,一是用instanceof 判断Handler 类型然后调用干系方法 。
二是通过引入适配器实现,每个适配器实现对指定Handler的调用。
spring 采取后者。

HandlerAdapter详解

HandlerAdapter中有三个接口

1supports接口,紧张的浸染是传入一个handler看看是否可以被实行。
如果可以返回true。

2handle处理接口,处理完返回一个ModelAndView。

3getLastModified,用作缓存处理,获取末了一次修正韶光。

我们知道HandlerAdapter对应适配了4种handler关系图如下。

举个例子,如果说我们写了一个Servlet,然后继续HttpServlet此时如果不配置SimpleServletHandlerAdapter适配器,那么就会报错,报500的非常。
但是如果配置了这个适配器,那么SpringMVC给我们配置的默认适配器SimpleControllerHandlerAdapter就会失落效。
以是须要手动的配置一下。
下面看一下源码即可验证这个说法。
上面讲到返回一个拦截器链条。
然后下面的代码便是获取适配器如下图。

点进getHandlerAdapter方法。
这个方法里做了一个do-while循环。
通过support方法判断是否是可用的适配器。

不才图的方法里判断是否是我们配置的适配器,如果是则返回true。
拿到适配器往后就开始了真正的调用。

此时适配器找到了往后就开始真正的调用handler也便是我们servlet或者是controller。
然后通过一个叫ViewResolver的接口类去解析。
个中有一个接口叫resolveViewName。
他返回一个View。
然后View里面有一个render接口。
通过里面的model进行处理,封装HTML。
通过response进行写入。
以是它是先有ViewResolver才有的View。

然后看看View有哪些实现类如下图。

第一个AbstractTemplateViewResolver里面有以下两种视图支持,比如我们常用的FreeMarkerViewReslover。

第二个BeanNameViewResolver可以通过这种办法实现自定的视图解析器,生明一个自定义View类。
然后实现View接口。
在render里面去做返回。
然后controller里面通过ModelAndView视图解析器的布局器去加载我们的自定义View类型。

第三个便是InternalResourceViewResolver。
这个便是我们最常用的,通过配置前缀,后缀等信息去实现视图解析。

下图是通过BeanName的形式做的视图解析

末了附上一张整体的流程图

封面图源网络,侵权删除)

私信头条号,发送:“资料”,获取更多“秘制” 佳构学习资料

如有收成,请帮忙转发,您的鼓励是作者最大的动力,感激!

一大波微做事、分布式、高并发、高可用的原创系列文章正在路上,

欢迎关注头条号:java小马哥

周一至周日早九点半!
下午三点半!
佳构技能文章定时送上!


十余年BAT架构履历倾囊相授