周一至周日早九点半!
下午三点半!
佳构技能文章定时送上!
!
!
佳构学习资料获取通道,拜会文末
1、回顾servlet 与jsp 实行过程
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架构履历倾囊相授