spring mvc之请求过程源码分析
简介
上一篇,我们分析了spring mvc启动过程的源码,这一节,来一起分析下在用户请求controller的过程中,spring mvc做了什么事?
一、准备
我写这么一个controller
package com.jacky.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.method.HandlerMethod; @Controller @RequestMapping("/bbb") public class IndexController { @RequestMapping(value = "/test.do", method = RequestMethod.GET) public String index() { return "index"; } @RequestMapping(value = "/aaa.do", method = RequestMethod.GET) @ResponseBody public String aaa() { return "aaa"; } }
二、用户请求controller的过程(http://localhost:8080/spring-mvc-demo/bbb/aaa.do)
上一篇,我们知道了,spring mcv基于servlet的,核心类是DispatcherServlet,那根据Servlet的知识,请求首先service()方法,但是在DispatherServlet中并没有找到service方法,在其父类FrameworkServlet中找到service方法,那我们就从这里看起。
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (HttpMethod.PATCH == httpMethod || httpMethod == null) { processRequest(request, response); } else { super.service(request, response); } }
2.1、接下来我们看处理请求方法processRequest(request, response)
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doService(request, response); }
2.2、接下来我们看看doService(request,response)方法
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { doDispatch(request, response); }
2.3、接下来我们看看DispatcherServlet的doDispatch(request,reponse)方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; ModelAndView mv = null; Exception dispatchException = null; processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); //根据请求获得请求执行链 mappedHandler = getHandler(processedRequest); //根据处理器获得对应的适配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //调用controller中的method的方法之前先调用拦截器的preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //根据请求调用controller中的method,然后返回ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //调用spring mvc拦截器的postHandle方法 mappedHandler.applyPostHandle(processedRequest, response, mv); }
这个方法里面有很多很关键的方法,没事我们一个个看里面的实现细节
2.4、首先我们看看获得请求执行链的方法getHandler(processedRequest)
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //遍历spring mvc启动时初始化好的handlerMappings(类型为List<HandlerMapping>) for (HandlerMapping hm : this.handlerMappings) { //利用handlerMaping取得处理器执行链 HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
2.5、接下来我们看看handlerMaping是怎么取得处理器执行链的?
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //获得HandlerMethod对象 Object handler = getHandlerInternal(request); //获得处理器执行链对象 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); return executionChain; }
2.6、首先我来看看怎么获得HandleMethod对象的
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { //获得请求路径,这里是lookupPath="/bbb/aaa.do" String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); //开启读锁 this.mappingRegistry.acquireReadLock(); try { //根据url获得HandleMethod HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { //释放读锁 this.mappingRegistry.releaseReadLock(); } }
2.7、接下来我们看看getHandlerExecutionChain是怎么获得处理器执行链的
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { //往处理器执行链的List<HandlerInterceptor>类型的interceptorList集合中,存放拦截器 chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }
从这里我们可以看到处理器其实封装了拦截器集合和一个handleMethod对象(封装了controller Class对象,浏览器请求的Controler中的method方法对象,参数)
2.8、上面,我们知道了,springMVC是怎么通过handleMaping获得handle(HandleMethod)对象,以及怎么添加拦截器,组装成处理器执行链,接下来我们继续看看springMVC是怎么获得处理器对应的
适配器的。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { //遍历spring mvc初始化时,设置的DispatcherServlet的成员变量List<HandlerAdapter> handlerAdapters for (HandlerAdapter ha : this.handlerAdapters) {
//判断适配器支不支持handler if (ha.supports(handler)) { return ha; } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
因为有会遍历很多种适配器,从上面我们知道,handlerd的类型是HandleMethod,所以的我们看的是RequestMappingHandlerAdapter适配器,根据RequestMappingHandlerAdapter的继承关系
可以知道,RequestMappingHandlerAdapter继承了AbstractHandlerMethodAdapter,在ha.supports(handler)方法中,刚好在AbstractHandlerMethodAdapter类中,我们来看看
public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); }
就是判断传入的handler是否是属于HandlerMethod类型的,如果是,就返回true,然后RequestMappingHandlerAdapter对象
2.9、springMVC怎么获得处理请求的适配器我们看完了,接下来,我们看看,获得适配器后,是怎么调用到controller中的对应的method的?
//根据请求调用controller中的method,然后返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
首先调用的是AbstractHandlerMethodAdapter类的handle方法
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); }
可以看到这个方法没干什么,只是调用了handleInternal方法,那我们就看看这个方法
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; mav = invokeHandlerMethod(request, response, handlerMethod); return mav; }
这个方法主要是调了invokeHandlerMethod方法,那我们继续来看卡这个方法干了什么?
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); //把handlerMethod封装成ServletInvocableHandlerMethod ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); //设置参数解析器 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); //设置spring mvc请求controller的method返回值处理器 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); invocableMethod.setDataBinderFactory(binderFactory); //设置参数名称发现器 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); invocableMethod.invokeAndHandle(webRequest, mavContainer); return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }
3.0、接下来我们看看真正的调用和处理方法invocableMethod.invokeAndHandle(webRequest, mavContainer);
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //在这里通过反射调用controller中的method方法 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(this.responseReason)) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); //在这里通过返回值处理器处理器进行二次处理,例如:如果加了方法加了reponseBody注解,就把结果序列化json字符串再返回 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); }