上面介绍了Spring MVC的使用,配置了一个DispatcherServlet作为所有请求的入口,DispatcherServlet继承自抽象类frameworkServlet,而frameworkServlet又继承自HttpServlet,所有当有请求进来时,会先进入到frameworkServlet的service()方法中,而在该方法中又会去调用父类HttpServlet的service()方法,该类的方法在《从Servlet到Spring MVC》中已经介绍过了,它会根据不同的请求去调用doGet()、doPost()等方法
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (httpMethod == HttpMethod.PATCH || httpMethod == null) { processRequest(request, response); } else { super.service(request, response); } }
而frameworkServlet中全部实现了这些doXxx()方法,而在这些doXxx()方法中,又都会去调用processRequest()方法
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } @Override protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }
在processRequest()方法中,除了加载一些上下文信息、绑定参数之后,最核心的就是去调用DispatcherServlet的doService()方法
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(frameworkServlet.class.getName(), new RequestBindingInterceptor()); initContextHolders(request, localeContext, requestAttributes); doService(request, response); }
在doService()方法中,会设置一些请求的参数,但最核心的是去调用doDispatch()方法,而doDispatch()才是SpringMVC处理请求最核心的方法,下面介绍一下doDispatch()方法的执行流程,以@RequestMapping注解为例,这个也是我们开发中用的最多的
1.1 获取处理器执行链在doDispatch()方法中,首先会去解析请求,得到一个处理器执行链,包含了拦截器集合和处理方法,而在映射的时候,就会用得到HandlerMapping,在《从Servlet到Spring MVC》中,介绍了如何配置HandlerMapping,如果没有配置,SpringMVC提供了四个默认的配置
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; // 进行映射 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } }
调用getHandler()方法就是去遍历所有的映射器处理器,看哪个能根据请求的url匹配到处理器方法
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; }1.1.1 获取处理器
调用getHandlerInternal()方法来获取处理器
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } …… }
首先获取request请求中的url,然后调用lookupHandlerMethod()去匹配
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 通过UrlPathHelper对象,用于来解析从们的request中解析出请求映射路径 String lookupPath = initLookupPath(request); this.mappingRegistry.acquireReadLock(); try { // 通过lookupPath解析最终的handler——HandlerMethod对象 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } }
在lookupHandlerMethod()中,根据url来匹配mappingRegistry.pathLookup,pathLookup是一个MultiValueMap,它最大的特点是value可以重复,所以同一个url可能会匹配到多个RequestMappingInfo
pathLookup的数据,是在SpringMVC容器启动的时候,就回去加载解析的,以@RequestMapping注解为例,在Bean实例化的过程中,就回去解析类中的方法是否有@RequestMapping注解,然后拼接url作为pathLookup的key,将类以及方法封装成RequestMappingInfo
如果通过pathLookup找到了url相匹配的处理器,这个时候还是不够,还需要去解析@RequestMapping注解中的mthod、header等属性是否匹配,RequestMappingInfo中包含了@RequestMapping注解所有配置的条件匹配器,比如ParamsRequestCondition、HeadersRequestCondition等
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { Listmatches = new ArrayList<>(); // pathLookup 会在初始化阶段解析好 List directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath); if (directPathMatches != null) { // 如果根据path能直接匹配的RequestMappingInfo 则用该mapping进行匹配其他条件(method、header等) addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // 如果无path匹配,用所有的RequestMappingInfo 通过AntPathMatcher匹配 addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request); } …… }
如果直接通过url没有在pathLookup找到,则会去调用getMatchingMapping()方法,通过pathMatcher来匹配,pathMatcher是一个AntPathMatcher类的实例,提供了按照通配符? * {匹配的逻辑
如果匹配到多个按照? > * > {} >**进行排序,然后取最匹配的那一个
protected String getMatchingMapping(String pattern, HttpServletRequest request) { String lookupPath = this.pathHelper.getLookupPathForRequest(request); String match = (this.pathMatcher.match(pattern, lookupPath) ? pattern : null); if (match != null) { this.matches.add(match); } return match; }1.1.2 封装处理器链
得到处理器之后,还需要取获取配置的拦截器,然后封装成一个执行器链
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } …… HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); }
调用getHandlerExecutionChain(),首先将处理器封装成一个HandlerExecutionChain,然后遍历配置的所有拦截器,只有与当前处理器匹配的,就加入到HandlerExecutionChain的interceptorList中,在执行执行器的方法前后,会调用拦截器的方法
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(request)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }1.2 获取处理器适配器
获取完处理器之后,就要为处理器匹配最合适的适配器,那么适配器是干嘛的,简单的来说就是解析参数的。
以@RequestMapping为例,它的方法参数,可以通过@RequestBody、@RequestParam等注解来获取参数,那么肯定就要有能够解析这些注解的适配器
如果没有通过Spring MVC的配置文件进行配置,默认有HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter和HandlerFunctionAdapter四种
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; // 进行映射 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 找到最合适的HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); }
寻找最合适的处理器适配器也很简单,遍历所有的是适配器,然后调用它们的support()方法进行匹配
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } }
supports()的方法也很简单,以HttpRequestHandlerAdapter为例:
只需要判断当前处理器是不是HttpRequestHandler的实现类即可,而RequestMappingHandlerAdapter的supports()方法永远返回true
public boolean supports(Object handler) { return (handler instanceof HttpRequestHandler); }1.3 执行处理器方法
在执行处理器的方法前,首先会去执行拦截器的前置方法
// 前置拦截器 if (!mappedHandler.applyPreHandle(processedRequest, response)) { // 返回false就不进行后续处理了 return; } boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { for (int i = 0; i < this.interceptorList.size(); i++) { HandlerInterceptor interceptor = this.interceptorList.get(i); if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } return true; } void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) { for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = this.interceptorList.get(i); interceptor.afterCompletion(request, response, this.handler, ex); } }
调用处理器的handle()方法,然后调用invokeHandlerMethod()方法设置一些常用的配置,比如:请求参数解析器、返回参数解析器、数据绑定器等,然后调用ServletInvocableHandlerMethod的invokeAndHandle()方法,执行处理器方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mv = null; mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); …… } protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { // 把我们的请求req resp包装成 ServletWebRequest ServletWebRequest webRequest = new ServletWebRequest(request, response); // 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中 // 配置的InitBinder,用于进行参数的绑定 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); // 获取容器中全局配置的ModelAttribute和当前HandlerMethod所对应的Controller 中配置的ModelAttribute, // 这些配置的方法将会在目标方法调用之前进行调用 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // 封装handlerMethod,会在调用前解析参数、调用后对返回值进行处理 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); if (this.argumentResolvers != null) { // 让invocableMethod拥有参数解析能力 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { // 让invocableMethod拥有返回值处理能力 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } // 让invocableMethod拥有InitBinder解析能力 invocableMethod.setDataBinderFactory(binderFactory); // 设置ParameterNameDiscoverer,该对象将按照一定的规则获取当前参数的名称 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); // ModelAndView处理容器 ModelAndViewContainer mavContainer = new ModelAndViewContainer(); // 将request的Attribute复制一份到ModelMap mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); // *调用我们标注了@ModelAttribute的方法,主要是为我们的目标方法预加载 modelFactory.initModel(webRequest, mavContainer, invocableMethod); // 重定向的时候,忽略model中的数据 默认false mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); // *对请求参数进行处理,调用目标HandlerMethod,并且将返回值封装为一个ModelAndView对象 invocableMethod.invokeAndHandle(webRequest, mavContainer); // 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向, // 还会判断是否需要将FlashAttributes封装到新的请求中 return getModelAndView(mavContainer, modelFactory, webRequest); }1.1.1 请求参数解析
在执行处理器方法之前,需要先解析参数,得到处理器方法参数列表的参数值
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { / Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); …… // 遍历当前容器中所有ReturnValueHandler,判断哪种handler支持当前返回值的处理, // 如果支持,则使用该handler处理该返回值 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); }
最后,调用getModelAndView()处理之前的ModelAndViewContainer,封装成一个ModelAndView对象
// 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向, // 还会判断是否需要将FlashAttributes封装到新的请求中 return getModelAndView(mavContainer, modelFactory, webRequest);1.4 视图解析
执行完处理器方法之后,接着是去执行所有拦截器的postHandle()方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 如果mv有 视图没有,给你设置默认视图 applyDefaultViewName(processedRequest, mv); //后置拦截器 mappedHandler.applyPostHandle(processedRequest, response, mv); void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { for (int i = this.interceptorList.size() - 1; i >= 0; i--) { HandlerInterceptor interceptor = this.interceptorList.get(i); interceptor.postHandle(request, response, this.handler, mv); } }
最后才是去渲染视图,在render()方法中,调用resolveViewName()方法去解析视图,然后返回一个View对象,最后调用View的render()方法去渲染视图
// 渲染视图 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { if (mv != null && !mv.wasCleared()) { // 解析、渲染视图 render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } } protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); View view; String viewName = mv.getViewName(); if (viewName != null) { // 解析视图名 view = resolveViewName(viewName, mv.getModelInternal(), locale, request); } if (mv.getStatus() != null) { response.setStatus(mv.getStatus().value()); } view.render(mv.getModelInternal(), request, response); }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)