SpringMVC执行流程

非 Y 不嫁゛ 提交于 2020-01-15 13:01:20

一、springMvc概念

springMvc是基于servlet的web框架,其简化了web程序的开发

二、springMvc请求流程

在阅读时不妨可以带着几个问题阅读:
1.我们通常在浏览器输入的接口怎么由DispatcherServlet调到具体的Handler的(就是我们自己开发的Controller类)
2.编写Controller的形式有哪几种?

springMvc重要组件:
之所以先说这几个组件,是因为只要了解了这几个组件后你便可以对springMvc请求流程有个大致的清晰认识了。(Handler就是我们写的Controller)
      HandlerMapping
      HandlerAdapter
      ViewResolver
      View
      HandlerExceptionResolver
      HandlerInterceptor
DisPatcher作为一个主流程入口,看一下DispatcherServlet结构

DispatcherServlet为了简洁,省去了很多方法跟属性

public class DispatcherServlet extends FrameworkServlet {
//定义了默认策略名字
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
private static final Properties defaultStrategies;
static {
            //从Properties文件中加载默认策略实现
            ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
            defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    }
private List<HandlerMapping> handlerMappings;
private List<HandlerAdapter> handlerAdapters;
private List<HandlerExceptionResolver> handlerExceptionResolvers;
private List<ViewResolver> viewResolvers;
//初始化策略
protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
            try {
            ModelAndView mv = null;
            Exception dispatchException = null;
            try {
                                //检查是否文件上传
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
                //通过HandlerMapping 获取Handler(返回的是HandlerExecutionChain)
               /**public class HandlerExecutionChain {
                       //HandlerExecutionChain封装了Handler(就是我们编写的Controller)跟interceptors
                       private final Object handler;
                       private HandlerInterceptor[] interceptors;
                **/
                HandlerExecutionChain mappedHandler = getHandler(processedRequest);
                //获取的Handler是Object类型,需要通过HandlerAdapter获取Handler真实类型
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                //调用Handlerinterceptor PreHandle(前置拦截器),返回false则停止执行
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // 调用真实handler逻辑并返回ModelAndView
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                                //将ModelAndView返回值DispatcherServlet后
                applyDefaultViewName(processedRequest, mv);
                                //调用Handlerinterceptor PostHandle(后置拦截器)    
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                // As of 4.3, we're processing Errors thrown from handler methods as well,
                // making them available for @ExceptionHandler methods and other scenarios.
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                                      //调用Handlerinterceptor afterCompletion
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }}

通过上面的DispatcherServlet大概分析可以得知几个组件的作用:
HandlerMapping:
根据请求url地址得到具体Handler(Controller)
HandlerAdapter
根据Handler得到Handler适配器
ViewResolver
试图仓库:根据ViewName得到View
View
具体解析视图
HandlerExceptionResolver
异常捕捕捉器
HandlerInterceptor
拦截器

三、springMvc处理流程图解:(引用他人流程图)

 
springMvc处理

简略图:


 
springMvc处理

四、各组件详解:

1.HandlerMapping
HandlerMapping方法:

 
HandlerMapping方法

HandlerMapping子类:
 
HandlerMapping

 

从上图看一看出常用的Mapping有三类:SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping、RequestMappingHandlerMapping。

RequestMappingHandlerMapping就是我们最长使用的方式基于注解@RequestMapping方式的url映射。
SimpleUrlHandlerMapping 基于手动配置 url 与control 映射

    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/hello">helloController</prop>
            </props>
        </property>
    </bean>
    <bean id="helloController" class="com.ckd.controller.HelloController"/>
-----------------------------------------------------------------------------------------------------------------------
import org.springframework.web.servlet.mvc.Controller;
public class HelloController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView mv = new ModelAndView("index");
        mv.addObject("hello","world");
        return mv;
    }
}

BeanNameUrlHandlerMapping是配置IOC bean时id以"/"开头与Controller的映射

<bean id="/beanname" class="com.ckd.controller.BeanNameController"/>
//需要继承HttpRequestHandler 此时可以把/beanname映射到handleRequest方法上
public class BeanNameControl implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        request.getRequestDispatcher("/WEB-INF/page/userView.jsp").forward(request, response);
    }
}

通过DisPatcherServlet.getHandler()获得Handler的类型时Object,此时无法调用,因此需要HandlerAdapter根据Handler获取具体的适配器
2.HandlerAdapter
springmvc采用适配器的模式适配调用Handler,根据handler不同调用不同的适配器,Handler与HandlerAdapter对用关系如下:

Handler类别对应适配器描述
Controller SimpleControllerHandlerAdapter 标准控制器,返回ModelAndView
HttpRequestHandler HttpRequestHandlerAdapter 业务自行处理 请求,不需要通过modelAndView 转到视图
Servlet SimpleServletHandlerAdapter 基于标准的servlet 处理
HandlerMethod RequestMappingHandlerAdapter 基于@requestMapping对应方法处理
 
image.png

 
image.png

基于Servlet演示

<bean class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/>
<bean id="/helloservlet" class="com.ckd.controller.HelloServlet"/>
----------------------------------------------------------------------------------------------------------------------------
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("hello Servlet");
    }
}

HelloServlet注册IOC容器中时,会由BeanNameUrlHandlerMapping找到对应的Handler,由SimpleServletHandlerAdapter找到对应的适配器,调用业务逻辑Controller,并返回ModelAndView。
3.ViewResolver View
DispatcherServlet#getHandlerAdapter().handle()后返回ModelAndView,
调用resolveViewName() 去viewResolvers试图列表中查找对应的View并返回View.交由View解析生成html并返回

 
ViewResolver

 

 

 
ViewResolver

 
View

4.HandlerExceptionResolver
该组件用于指示 当出现异常时 mvc 该如何处理。 dispatcherServlet 会调用org.springframework.web.servlet.DispatcherServlet#processHandlerException() 方法,遍历 handlerExceptionResolvers 处理异常,处理完成之后返回errorView 跳转到异常视图。
- [ ] 演示自定义异常捕捉

 

<bean class="com.ckd.controller.ExceptionHandlerSample"/>
public class ExceptionHandlerSample implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        return new ModelAndView("error");
    }
}

 

 
image.png

5.HandlerInterceptor

 

  • [ ] 演示HandlerInterceptor
<mvc:interceptors>
        <mvc:interceptor>
            <!-- 拦截所有的请求,这个必须写在前面-->
            <mvc:mapping path="/**" />            
            <bean class="com.ckd.controller.SimpleHandlerInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>
-----------------------------------------------------------------------------------------------------------------------------------------
public class SimpleHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

其实现机制是基于 HandlerExecutionChain 分别在 doDispatch 方法中执行以下方法:

  • preHandle :业务处理前执行
  • postHandle:业务处理后(异常则不执行)
  • afterCompletion:视图处理后

具体逻辑源码参见:org.springframework.web.servlet.DispatcherServlet#doDispatch 方法。



转载:https://www.jianshu.com/p/c68cf985f877

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!