zoukankan      html  css  js  c++  java
  • SpringMVC工作原理

    总结:在javax.servlet.http.HttpServlet的基础上添加额外功能,包括参数解析、请求拦截器、异常处理、视图渲染等。

     

    Handler

    springframework中对http request的最细粒度的处理者,类似于javax中的Servlet。类型有:

    org.springframework.web.HttpRequestHandler:接口,有很多实现类,如ResourceHttpRequestHandler专门用于处理静态资源请求

    org.springframework.web.servlet.mvc.Controller:接口,有很多实现类,如ServletWrappingController。

    org.springframework.web.method.HandlerMethod:类,springframework的@Controller中带有@RequestMapping的方法默认为此类的handler

    HandlerAdapter

    具体执行handler方法者,DispatcherServlet会根据handler的类型交由相应的handler adapter执行。默认会添加三个HandlerAdapter到application context:

    class org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,处理interface org.springframework.web.HttpRequestHandler类型的handler

    class org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,处理interface org.springframework.web.servlet.mvc.Controller类型的handler

    class org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,处理class org.springframework.web.method.HandlerMethod类型的handler,@Controller中的handler通过此adapter处理

    HandlerMapping

    接口,用于定义request和handler间的对应关系,将依据此确定request由哪个handler处理。springframework默认有两种HandlerMapping的实现方式,当application context中没有HandlerMapping Bean时默认采用前者,但实际上通常会将后者注册为Bean。

    BeanNameUrlHandlerMapping:map from URLs to beans with names that start with a slash ("/"),即将url映射到与url同名的Bean上

    RequestMappingHandlerMapping:Creates RequestMappingInfo instances from type and method-level @RequestMapping annotations in @Controller classes,即建立url与handler间的对应关系。默认为此。在程序启动时springframework会自动扫描并建立该对应关系。可以重写该类的方法来自定义关联规则,如当前项目引入其他项目的Feign Client时被引项目的handler也会被当前项目的HandlerMapping识别成当前项目的接口,可通过重写规避:

    @Configuration
    @ConditionalOnClass({ Feign.class })
    public class FeignConfiguration {// 解决@FeignClient中的@RequestMapping也被当前项目识别成Handler的问题
    
        @Bean
        public WebMvcRegistrations feignWebRegistrations() {
            return new WebMvcRegistrations() {
                @Override
                public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
                    return new FeignRequestMappingHandlerMapping();
                }
            };
        }
    
        private static class FeignRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
            @Override
            protected boolean isHandler(Class<?> beanType) {
                return super.isHandler(beanType) && !AnnotatedElementUtils.hasAnnotation(beanType, FeignClient.class);
            }
        }
    }
    View Code

    DispatcherServlet

    继承HttpServlet,传统java Servlet项目中每个文件为一个Servlet,而这里一个DispatcherServlet类作为一个Servlet,起网关的作用,路由到与请求url相应的handler。

    详细逻辑可参阅其doDispatch方法,主要过程:

    根据HandlerMapping获取handler with any interceptor,即HandlerExecutionChain实例。support该handler的HandlerMapping可能有多个,按顺序遍历,成功获取到HandlerExecutionChain实例即止(获取的过程HandlerExecutionChain实质上是调用AbstractUrlHandlerMapping.lookupHandler,即根据url找对应的hanlder)。

        @Nullable
        protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            if (this.handlerMappings != null) {
                for (HandlerMapping mapping : this.handlerMappings) {
                    HandlerExecutionChain handler = mapping.getHandler(request);
                    if (handler != null) {
                        return handler;
                    }
                }
            }
            return null;
        }
    View Code

    根据handler获取处理该handler的HandlerAdaptor实例,support该handler的HandlerAdaptor可能有多个,按顺序遍历HandlerAdaptor列表取第一个support者。

        protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
            if (this.handlerAdapters != null) {
                for (HandlerAdapter adapter : this.handlerAdapters) {
                    if (adapter.supports(handler)) {
                        return adapter;
                    }
                }
            }
            throw new ServletException("No adapter for handler [" + handler +
                    "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
        }
    View Code

    根据HandlerExecutionChain实例执行所有Interceptor的preHandle方法

    根据HandlerAdaptor实例执行目标handler方法

    根据HandlerExecutionChain实例执行所有Interceptor的postHandle方法

    对执行结果进行处理(processDispatchResult),包括:

    1、处理异常(processHandlerException)或解析视图(render),二选一;

    2、执行各Interceptor的afterCompletion方法

     

    可见,DispatcherServlet通过调用HandlerMapping.getHandler方法获取处理当前请求的handler(HandlerMapping可能有多个,按优先级依次尝试通过HandlerMapping获取handler,成功即止),获取到的不是纯handler,而是HandlerExecutionChain,其封装了handler及针对hanlder的拦截器。DispatcherServlet会依次调用各拦截器方法再调用目标handler方法。

    A handler will always be wrapped in a HandlerExecutionChain instance, optionally accompanied by some HandlerInterceptor instances. The DispatcherServlet will first call each HandlerInterceptor's preHandle method in the given order, finally invoking the handler itself if all preHandle methods have returned true.
    View Code

    默认情况下,对于request如果没有找到与url对应的controller方法,则会当做请求静态资源来处理(对应的Handler、HandlerAdaptor分别为ResourceHttpRequestHandler、HttpRequestHandlerAdapter来处理),尝试从配置的各static resouce路径下获取该url对应的资源。

    ViewResolver

    解析视图

    HandlerExceptionResolver

    处理handler执行的异常,会依次调用各HandlerExceptionResolver的resolveException方法,若有一个返回非null则结束。

    只需要实现HandlerExceptionResolver接口并重写resolveException方法即可实现自定义的异常处理。

    转自:https://www.cnblogs.com/xiaoxi/p/6164383.html,以下为正文。

    SpringMVC的工作原理图:

    SpringMVC流程

    1、  用户发送请求至前端控制器DispatcherServlet。

    2、  DispatcherServlet收到请求调用HandlerMapping处理器映射器。

    3、  处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

    4、  DispatcherServlet调用HandlerAdapter处理器适配器。

    5、  HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

    6、  Controller执行完成返回ModelAndView。

    7、  HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

    8、  DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

    9、  ViewReslover解析后返回具体View。

    10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

    11、 DispatcherServlet响应用户。

    组件说明:

    以下组件通常使用框架提供实现:

    DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。

    HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。 

    HandlAdapter:通过扩展处理器适配器,支持更多类型的处理器。

    ViewResolver:通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。

    组件:
    1、前端控制器DispatcherServlet(不需要工程师开发),由框架提供
    作用:接收请求,响应结果,相当于转发器,中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。
    用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。

    2、处理器映射器HandlerMapping(不需要工程师开发),由框架提供
    作用:根据请求的url查找Handler
    HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

    3、处理器适配器HandlerAdapter
    作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
    通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

    4、处理器Handler(需要工程师开发)
    注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
    Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
    由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。

    5、视图解析器View resolver(不需要工程师开发),由框架提供
    作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
    View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。
    一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。

    6、视图View(需要工程师开发jsp...)
    View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)

    核心架构的具体流程步骤如下:
    1、首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
    2、DispatcherServlet——>HandlerMapping, HandlerMapping 将会把请求映射为HandlerExecutionChain 对象(包含一个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
    3、DispatcherServlet——>HandlerAdapter,HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
    4、HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView 对象(包含模型数据、逻辑视图名);
    5、ModelAndView的逻辑视图名——> ViewResolver, ViewResolver 将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
    6、View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
    7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。

    下边两个组件通常情况下需要开发:

    Handler:处理器,即后端控制器用controller表示。

    View:视图,即展示给用户的界面,视图中通常需要标签语言展示模型数据。

    在将SpringMVC之前我们先来看一下什么是MVC模式

    MVC:MVC是一种设计模式

    MVC的原理图:

    分析:

    M-Model 模型(完成业务逻辑:有javaBean构成,service+dao+entity)

    V-View 视图(做界面的展示  jsp,html……)

    C-Controller 控制器(接收请求—>调用模型—>根据结果派发页面)

     

    springMVC是什么: 

      springMVC是一个MVC的开源框架,springMVC=struts2+spring,springMVC就相当于是Struts2加上sring的整合,但是这里有一个疑惑就是,springMVC和spring是什么样的关系呢?这个在百度百科上有一个很好的解释:意思是说,springMVC是spring的一个后续产品,其实就是spring在原有基础上,又提供了web应用的MVC模块,可以简单的把springMVC理解为是spring的一个模块(类似AOP,IOC这样的模块),网络上经常会说springMVC和spring无缝集成,其实springMVC就是spring的一个子模块,所以根本不需要同spring进行整合。

    SpringMVC的原理图:

    看到这个图大家可能会有很多的疑惑,现在我们来看一下这个图的步骤:(可以对比MVC的原理图进行理解)

    第一步:用户发起请求到前端控制器(DispatcherServlet)

    第二步:前端控制器请求处理器映射器(HandlerMappering)去查找处理器(Handle):通过xml配置或者注解进行查找

    第三步:找到以后处理器映射器(HandlerMappering)像前端控制器返回执行链(HandlerExecutionChain)

    第四步:前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)去执行处理器(Handler)

    第五步:处理器适配器去执行Handler

    第六步:Handler执行完给处理器适配器返回ModelAndView

    第七步:处理器适配器向前端控制器返回ModelAndView

    第八步:前端控制器请求视图解析器(ViewResolver)去进行视图解析

    第九步:视图解析器像前端控制器返回View

    第十步:前端控制器对视图进行渲染

    第十一步:前端控制器向用户响应结果

    看到这些步骤我相信大家很感觉非常的乱,这是正常的,但是这里主要是要大家理解springMVC中的几个组件:

    前端控制器(DispatcherServlet):接收请求,响应结果,相当于电脑的CPU。

    处理器映射器(HandlerMapping):根据URL去查找处理器

    处理器(Handler):(需要程序员去写代码处理逻辑的)

    处理器适配器(HandlerAdapter):会把处理器包装成适配器,这样就可以支持多种类型的处理器,类比笔记本的适配器(适配器模式的应用)

    视图解析器(ViewResovler):进行视图解析,多返回的字符串,进行处理,可以解析成对应的页面

  • 相关阅读:
    codeforces 985 F. Isomorphic Strings
    Educational Codeforces Round 44
    codeforces 979D
    ARC060 Digit Sum II
    Iroha and Haiku II
    Unhappy Hacking II
    Just h-index 2018湘潭邀请赛
    [HAOI2007]理想的正方形
    P1231 教辅的组成
    最小割数学形式
  • 原文地址:https://www.cnblogs.com/z-sm/p/12834647.html
Copyright © 2011-2022 走看看