Springmvc 工作机制源码分析

    xiaoxiao2021-12-14  21

    Springmvc整体工作流程

            DispatcherServlet本质是HttpServlet,是Springmvc的http请求分发控制器,是Springmvc整体工作流程的核心。

    DispatcherServlet类结构继承图

    在../WEB-INF/web.xml中配置如下:

    <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/META-INF/spring/springmvc-servlet.xml</param-value> </init-param> <!-- <load-on-startup>1</load-on-startup> --> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>

             通过在web.xml中配置contextConfigLocation,指定了Springmvc的核心配置文件。

    Springmvc整体工作流程示意图

    Springmvc整体工作流程实现简图

    初始化

               Springmvc的初始化体现为DispatcherServlet的初始化:1)完成Springmvc容器XmlWebApplicationContext的创建、配置及refresh;2)完成其组件的初始化。

    Springmvc核心配置文件springmvc-servlet.xml

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <!-- scan the package and the sub package --> <context:component-scan base-package="com.bitvalue"/> <!-- don't handle the static resource --> <mvc:default-servlet-handler /> <!-- if you use annotation you must configure following setting --> <mvc:annotation-driven /> <!-- configure the InternalResourceViewResolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/pages/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> </bean> <!-- 支持上传文件 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/> <!-- 拦截器 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/test/**" /> <bean class="org.test.interceptor.TestInterceptor"/> </mvc:interceptor> </mvc:interceptors> </beans>

    XmlWebApplicationContext容器的创建、配置及refresh

    组件初始化

    相关源码

             在“XmlWebApplicationContext容器的创建、配置及refresh”初始化阶段涉及Springmvc配置文件的解析及XmlWebApplicationContext容器中相关bean的实例化。

    <mvc>标签元素解析

    /** MvcNamespaceHandler.java */ public class MvcNamespaceHandler extends NamespaceHandlerSupport { // <mvc>相应标签元素解析 public void init() { // 注册<mvc:annotation-driven />解析的BeanDefinitionParser registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); // 注册<mvc:default-servlet-handler />解析的BeanDefinitionParser registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser()); // 注册<mvc:interceptors />解析的BeanDefinitionParser registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser()); // 注册<mvc:resources />解析的BeanDefinitionParser registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser()); // 注册<mvc:view-controller />解析的BeanDefinitionParser registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser()); } } /** AnnotationDrivenBeanDefinitionParser.java */ public BeanDefinition parse(Element element, ParserContext parserContext) { Object source = parserContext.extractSource(element); CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source); parserContext.pushContainingComponent(compDefinition); RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext); // RequestMappingHandlerMapping RootBeanDefinition RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class); handlerMappingDef.setSource(source); handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); handlerMappingDef.getPropertyValues().add("order", 0); handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager); String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(handlerMappingDef); if (element.hasAttribute("enableMatrixVariables")) { Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enableMatrixVariables")); handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables); } RuntimeBeanReference conversionService = getConversionService(element, source, parserContext); RuntimeBeanReference validator = getValidator(element, source, parserContext); RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element); // ConfigurableWebBindingInitializer RootBeanDefinition RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class); bindingDef.setSource(source); bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); bindingDef.getPropertyValues().add("conversionService", conversionService); bindingDef.getPropertyValues().add("validator", validator); bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver); ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext); ManagedList<?> argumentResolvers = getArgumentResolvers(element, parserContext); ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext); String asyncTimeout = getAsyncTimeout(element); RuntimeBeanReference asyncExecutor = getAsyncExecutor(element); ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, parserContext); ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext); // RequestMappingHandlerAdapter RootBeanDefinition RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); handlerAdapterDef.setSource(source); handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager); handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef); handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters); if (element.hasAttribute("ignoreDefaultModelOnRedirect")) { Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect")); handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel); } if (argumentResolvers != null) { handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers); } if (returnValueHandlers != null) { handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers); } if (asyncTimeout != null) { handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout); } if (asyncExecutor != null) { handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor); } handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors); handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors); String handlerAdapterName = parserContext.getReaderContext().registerWithGeneratedName(handlerAdapterDef); // ConversionServiceExposingInterceptor RootBeanDefinition RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class); csInterceptorDef.setSource(source); csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService); // MappedInterceptor RootBeanDefinition RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class); mappedCsInterceptorDef.setSource(source); mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null); mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef); String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef); // ExceptionHandlerExceptionResolver RootBeanDefinition RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class); exceptionHandlerExceptionResolver.setSource(source); exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager); exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters); exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0); String methodExceptionResolverName = parserContext.getReaderContext().registerWithGeneratedName(exceptionHandlerExceptionResolver); // ResponseStatusExceptionResolver RootBeanDefinition RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class); responseStatusExceptionResolver.setSource(source); responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); responseStatusExceptionResolver.getPropertyValues().add("order", 1); String responseStatusExceptionResolverName = parserContext.getReaderContext().registerWithGeneratedName(responseStatusExceptionResolver); // DefaultHandlerExceptionResolver RootBeanDefinition RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class); defaultExceptionResolver.setSource(source); defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); defaultExceptionResolver.getPropertyValues().add("order", 2); String defaultExceptionResolverName = parserContext.getReaderContext().registerWithGeneratedName(defaultExceptionResolver); parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, methodMappingName)); parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, handlerAdapterName)); parserContext.registerComponent(new BeanComponentDefinition(exceptionHandlerExceptionResolver, methodExceptionResolverName)); parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName)); parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName)); parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName)); // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off" MvcNamespaceUtils.registerDefaultComponents(parserContext, source); parserContext.popAndRegisterContainingComponent(); return null; } /** DefaultServletHandlerBeanDefinitionParser.java */ public BeanDefinition parse(Element element, ParserContext parserContext) { Object source = parserContext.extractSource(element); String defaultServletName = element.getAttribute("default-servlet-name"); // DefaultServletHttpRequestHandler RootBeanDefinition RootBeanDefinition defaultServletHandlerDef = new RootBeanDefinition(DefaultServletHttpRequestHandler.class); defaultServletHandlerDef.setSource(source); defaultServletHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); if (StringUtils.hasText(defaultServletName)) { defaultServletHandlerDef.getPropertyValues().add("defaultServletName", defaultServletName); } String defaultServletHandlerName = parserContext.getReaderContext().generateBeanName(defaultServletHandlerDef); parserContext.getRegistry().registerBeanDefinition(defaultServletHandlerName, defaultServletHandlerDef); parserContext.registerComponent(new BeanComponentDefinition(defaultServletHandlerDef, defaultServletHandlerName)); Map<String, String> urlMap = new ManagedMap<String, String>(); urlMap.put("/**", defaultServletHandlerName); // SimpleUrlHandlerMapping RootBeanDefinition RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class); handlerMappingDef.setSource(source); handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); handlerMappingDef.getPropertyValues().add("urlMap", urlMap); String handlerMappingBeanName = parserContext.getReaderContext().generateBeanName(handlerMappingDef); parserContext.getRegistry().registerBeanDefinition(handlerMappingBeanName, handlerMappingDef); parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, handlerMappingBeanName)); // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off" MvcNamespaceUtils.registerDefaultComponents(parserContext, source); return null; } /** InterceptorsBeanDefinitionParser.java */ public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compDefinition); List<Element> interceptors = DomUtils.getChildElementsByTagName(element, "bean", "ref", "interceptor"); for (Element interceptor : interceptors) { // MappedInterceptor RootBeanDefinition RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class); mappedInterceptorDef.setSource(parserContext.extractSource(interceptor)); mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); ManagedList<String> includePatterns = null; ManagedList<String> excludePatterns = null; Object interceptorBean; if ("interceptor".equals(interceptor.getLocalName())) { includePatterns = getIncludePatterns(interceptor, "mapping"); excludePatterns = getIncludePatterns(interceptor, "exclude-mapping"); Element beanElem = DomUtils.getChildElementsByTagName(interceptor, "bean", "ref").get(0); interceptorBean = parserContext.getDelegate().parsePropertySubElement(beanElem, null); } else { interceptorBean = parserContext.getDelegate().parsePropertySubElement(interceptor, null); } mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, includePatterns); mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, excludePatterns); mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(2, interceptorBean); String beanName = parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef); parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, beanName)); } parserContext.popAndRegisterContainingComponent(); return null; }

    RequestMappingHandlerMapping bean初始化

            RequestMappingHandlerMapping的初始化主要工作为建立请求url与HandlerMethod的映射关系。

    AbstractHandlerMapping类结构关系图:

    时序图:

    相关源码:

    /** AbstractHandlerMethodMapping.java */ protected void detectHandlerMethods(final Object handler) { Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); // Avoid repeated calls to getMappingForMethod which would rebuild RequestMatchingInfo instances final Map<Method, T> mappings = new IdentityHashMap<Method, T>(); final Class<?> userType = ClassUtils.getUserClass(handlerType); // 查找userType中带@RequestMapping注解的method Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { public boolean matches(Method method) { // 过滤带@RequestMapping注解的method,用@RequestMapping注解的属性值,new RequestMappingInfo T mapping = getMappingForMethod(method, userType); if (mapping != null) { mappings.put(method, mapping); return true; } else { return false; } } }); for (Method method : methods) { //创建HandlerMethod且缓存其与url等的映射关系 registerHandlerMethod(handler, method, mappings.get(method)); } } /** RequestMappingHandlerMapping.java */ protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { RequestMappingInfo info = null; // method上的@RequestMapping注解对象 RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class); if (methodAnnotation != null) { RequestCondition<?> methodCondition = getCustomMethodCondition(method); info = createRequestMappingInfo(methodAnnotation, methodCondition); // Class上的@RequestMapping注解对象 RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); if (typeAnnotation != null) { RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType); // 相关属性合并 info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info); } } return info; } /** AbstractHandlerMethodMapping.java */ protected void registerHandlerMethod(Object handler, Method method, T mapping) { //创建HandlerMethod HandlerMethod newHandlerMethod = createHandlerMethod(handler, method); HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping); if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) { throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() + "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" + oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped."); } //RequestMappingInfo到HandlerMethod映射 this.handlerMethods.put(mapping, newHandlerMethod); if (logger.isInfoEnabled()) { logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod); } Set<String> patterns = getMappingPathPatterns(mapping); for (String pattern : patterns) { if (!getPathMatcher().isPattern(pattern)) { // url到RequestMappingInfo映射 this.urlMap.add(pattern, mapping); } } } protected HandlerMethod createHandlerMethod(Object handler, Method method) { HandlerMethod handlerMethod; if (handler instanceof String) { String beanName = (String) handler; handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method); } else { handlerMethod = new HandlerMethod(handler, method); } return handlerMethod; } /** RequestMappingInfoHandlerMapping.java */ protected Set<String> getMappingPathPatterns(RequestMappingInfo info) { return info.getPatternsCondition().getPatterns(); }

    一次http请求处理流程

    整体流程

    getHandler流程

    时序图:

    相关源码:

    /** AbstractHandlerMethodMapping.java */ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<Match>(); // 根据url获取RequestMappingInfo List<T> directPathMatches = this.urlMap.get(lookupPath); if (directPathMatches != null) { // 匹配request的RequestMappingInfo addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings... addMatchingMappings(this.handlerMethods.keySet(), matches, request); } if (!matches.isEmpty()) { Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); Collections.sort(matches, comparator); if (logger.isTraceEnabled()) { logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); } // 最佳匹配request的Match Match bestMatch = matches.get(0); if (matches.size() > 1) { Match secondBestMatch = matches.get(1); if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); throw new IllegalStateException( "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}"); } } handleMatch(bestMatch.mapping, lookupPath, request); // 最佳匹配request的handlerMethod return bestMatch.handlerMethod; } else { return handleNoMatch(handlerMethods.keySet(), lookupPath, request); } } private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) { for (T mapping : mappings) { // 根据request,获取匹配的RequestMappingInfo T match = getMatchingMapping(mapping, request); if (match != null) { matches.add(new Match(match, this.handlerMethods.get(mapping))); } } } /** RequestMappingInfoHandlerMapping.java */ protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) { return info.getMatchingCondition(request); } /** RequestMappingInfo.java */ // 根据request,获取匹配的RequestMappingInfo public RequestMappingInfo getMatchingCondition(HttpServletRequest request) { RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request); ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request); HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request); ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request); ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request); if (methods == null || params == null || headers == null || consumes == null || produces == null) { return null; } PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request); if (patterns == null) { return null; } RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request); if (custom == null) { return null; } return new RequestMappingInfo(patterns, methods, params, headers, consumes, produces, custom.getCondition()); } /** RequestMappingInfoHandlerMapping.java */ protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) { // request设置org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping属性 super.handleMatch(info, lookupPath, request); String bestPattern; Map<String, String> uriVariables; Map<String, String> decodedUriVariables; Set<String> patterns = info.getPatternsCondition().getPatterns(); if (patterns.isEmpty()) { bestPattern = lookupPath; uriVariables = Collections.emptyMap(); decodedUriVariables = Collections.emptyMap(); } else { bestPattern = patterns.iterator().next(); uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath); decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables); } // request设置org.springframework.web.servlet.HandlerMapping.bestMatchingPattern属性 request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern); // request设置org.springframework.web.servlet.HandlerMapping.uriTemplateVariables属性 request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables); if (isMatrixVariableContentAvailable()) { Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables); request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars); } if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) { Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes(); request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes); } } /** AbstractHandlerMapping.java */ // 创建执行请求的处理链HandlerExecutionChain(拦截器+HandlerMethod) protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); chain.addInterceptors(getAdaptedInterceptors()); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); // 根据请求的lookupPath,获取匹配该url的拦截器 for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) { if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } return chain; }

    getHandlerAdapter流程

    /** DispatcherServlet.java */ protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } 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"); }

    HandlerAdapter handle流程

    HandlerAdapter类结构关系图:

    时序图:

    相关源码:

    /** RequestMappingHandlerAdapter.java */ // 调用HandlerMethod返回结果ModelAndView private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); //数据绑定Factory WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory); //缓存调用结果Model、View ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, requestMappingMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this.taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this.callableInterceptors); asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0]; asyncManager.clearConcurrentResult(); if (logger.isDebugEnabled()) { logger.debug("Found concurrent result value [" + result + "]"); } requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result); } // 调用HandlerMethod,且处理返回结果到mavContainer requestMappingMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } // 从mavContainer获取ModelAndView return getModelAndView(mavContainer, modelFactory, webRequest); } /** ServletInvocableHandlerMethod.java */ public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 调用HandlerMethod 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); try { // 处理returnValue,将结果ModelAndView中的ModelMap键值对合并到mavContainer this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex); } throw ex; } } /** InvocableHandlerMethod.java */ // 实际调用HandlerMethod public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 获取HandlerMethod参数值 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { StringBuilder sb = new StringBuilder("Invoking ["); sb.append(getBeanType().getSimpleName()).append("."); sb.append(getMethod().getName()).append("] method with arguments "); sb.append(Arrays.asList(args)); logger.trace(sb.toString()); } // 利用反射实际调用HandlerMethod Object returnValue = invoke(args); if (logger.isTraceEnabled()) { logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]"); } return returnValue; } private Object invoke(Object... args) throws Exception { ReflectionUtils.makeAccessible(getBridgedMethod()); try { return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); throw new IllegalStateException(getInvocationErrorMessage(ex.getMessage(), args), ex); } catch (InvocationTargetException ex) { // Unwrap for HandlerExceptionResolvers ... Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { String msg = getInvocationErrorMessage("Failed to invoke controller method", args); throw new IllegalStateException(msg, targetException); } } } /** HandlerMethodReturnValueHandlerComposite.java */ public void handleReturnValue( Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 获取ReturnValueHandler HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType); Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]"); // 处理ReturnValue handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); } /** ModelAndViewMethodReturnValueHandler.java */ public void handleReturnValue( Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue == null) { mavContainer.setRequestHandled(true); return; } ModelAndView mav = (ModelAndView) returnValue; // viewName带"redirect:"则设置redirectModelScenario为true if (mav.isReference()) { String viewName = mav.getViewName(); mavContainer.setViewName(viewName); if (viewName != null && viewName.startsWith("redirect:")) { mavContainer.setRedirectModelScenario(true); } } else { View view = mav.getView(); mavContainer.setView(view); if (view instanceof SmartView) { if (((SmartView) view).isRedirectView()) { mavContainer.setRedirectModelScenario(true); } } } // mav中的ModelMap的属性键值对合并到mavContainer mavContainer.addAllAttributes(mav.getModel()); } /** RequestMappingHandlerAdapter.java */ // 从mavContainer提取ModelAndView private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav; }

    processDispatchResult流程

    /** DispatcherServlet.java */ private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { // 完成model到view的渲染,返回给前端 render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { // 调用拦截器链afterCompletion方法 mappedHandler.triggerAfterCompletion(request, response, null); } } protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // 确定Locale语言zh_CN Locale locale = this.localeResolver.resolveLocale(request); response.setLocale(locale); View view; if (mv.isReference()) { // 根据viewName,借助viewResolver解析,获取view view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + getServletName() + "'"); } } else { // No need to lookup: the ModelAndView object contains the actual View object. view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name '" + getServletName() + "'"); } } // Delegate to the View object for rendering. if (logger.isDebugEnabled()) { logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'"); } try { // 将model中的键值对输出到request,利用RequestDispatcher渲染到jsp等前端页面上 view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'", ex); } throw ex; } } protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { for (ViewResolver viewResolver : this.viewResolvers) { // viewResolver确定view View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } return null; } /** AbstractCachingViewResolver.java(InternalResourceViewResolver.java) */ public View resolveViewName(String viewName, Locale locale) throws Exception { if (!isCache()) { return createView(viewName, locale); } else { Object cacheKey = getCacheKey(viewName, locale); View view = this.viewAccessCache.get(cacheKey); if (view == null) { synchronized (this.viewCreationCache) { view = this.viewCreationCache.get(cacheKey); if (view == null) { // 创建view view = createView(viewName, locale); if (view == null && this.cacheUnresolved) { view = UNRESOLVED_VIEW; } if (view != null) { // 缓存view this.viewAccessCache.put(cacheKey, view); this.viewCreationCache.put(cacheKey, view); if (logger.isTraceEnabled()) { logger.trace("Cached view [" + cacheKey + "]"); } } } } } return (view != UNRESOLVED_VIEW ? view : null); } } /** UrlBasedViewResolver.java(InternalResourceViewResolver.java) */ protected View createView(String viewName, Locale locale) throws Exception { // If this resolver is not supposed to handle the given view, // return null to pass on to the next resolver in the chain. if (!canHandle(viewName, locale)) { return null; } // viewName前缀为"redirect:",创建RedirectView if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); return applyLifecycleMethods(viewName, view); } // viewName前缀为"forward:",创建InternalResourceView if (viewName.startsWith(FORWARD_URL_PREFIX)) { String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length()); return new InternalResourceView(forwardUrl); } // 直接创建View return super.createView(viewName, locale); } protected View loadView(String viewName, Locale locale) throws Exception { // 创建view AbstractUrlBasedView view = buildView(viewName); // 初始化view bean View result = applyLifecycleMethods(viewName, view); return (view.checkResource(locale) ? result : null); } private View applyLifecycleMethods(String viewName, AbstractView view) { return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName); } /** InternalResourceViewResolver.java */ protected AbstractUrlBasedView buildView(String viewName) throws Exception { InternalResourceView view = (InternalResourceView) super.buildView(viewName); if (this.alwaysInclude != null) { view.setAlwaysInclude(this.alwaysInclude); } if (this.exposeContextBeansAsAttributes != null) { view.setExposeContextBeansAsAttributes(this.exposeContextBeansAsAttributes); } if (this.exposedContextBeanNames != null) { view.setExposedContextBeanNames(this.exposedContextBeanNames); } view.setPreventDispatchLoop(true); return view; } /** UrlBasedViewResolver.java(InternalResourceViewResolver.java) */ protected AbstractUrlBasedView buildView(String viewName) throws Exception { // 用反射实例化view AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass()); // 设置view对应的url,例如/WEB-INF/pages/index.jsp view.setUrl(getPrefix() + viewName + getSuffix()); String contentType = getContentType(); if (contentType != null) { view.setContentType(contentType); } view.setRequestContextAttribute(getRequestContextAttribute()); view.setAttributesMap(getAttributesMap()); if (this.exposePathVariables != null) { view.setExposePathVariables(exposePathVariables); } return view; } /** AbstractView.java(JstlView.java) */ public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isTraceEnabled()) { logger.trace("Rendering view with name '" + this.beanName + "' with model " + model + " and static attributes " + this.staticAttributes); } // 合并model中的键值对 Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); renderMergedOutputModel(mergedModel, request, response); } protected Map<String, Object> createMergedOutputModel(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) { @SuppressWarnings("unchecked") Map<String, Object> pathVars = (this.exposePathVariables ? (Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null); // Consolidate static and dynamic model attributes. int size = this.staticAttributes.size(); size += (model != null) ? model.size() : 0; size += (pathVars != null) ? pathVars.size() : 0; Map<String, Object> mergedModel = new LinkedHashMap<String, Object>(size); mergedModel.putAll(this.staticAttributes); if (pathVars != null) { mergedModel.putAll(pathVars); } if (model != null) { mergedModel.putAll(model); } // Expose RequestContext? if (this.requestContextAttribute != null) { mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel)); } return mergedModel; } /** InternalResourceView.java(JstlView.java) */ protected void renderMergedOutputModel( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine which request handle to expose to the RequestDispatcher. HttpServletRequest requestToExpose = getRequestToExpose(request); // 将model中的键值对输出到request,做为request的Attribute exposeModelAsRequestAttributes(model, requestToExpose); // 在request属性中设置LocalizationContext键值对 exposeHelpers(requestToExpose); // 确定request dispatcher的url String dispatcherPath = prepareForRendering(requestToExpose, response); // 获取RequestDispatcher RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath); if (rd == null) { throw new ServletException("Could not get RequestDispatcher for [" + getUrl() + "]: Check that the corresponding file exists within your web application archive!"); } // 完成model到view的渲染,返回给前端 // If already included or response already committed, perform include, else forward. if (useInclude(requestToExpose, response)) { response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } rd.include(requestToExpose, response); } else { // Note: The forwarded resource is supposed to determine the content type itself. exposeForwardRequestAttributes(requestToExpose); if (logger.isDebugEnabled()) { logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } rd.forward(requestToExpose, response); } } /** AbstractView.java(JstlView.java) */ protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception { for (Map.Entry<String, Object> entry : model.entrySet()) { String modelName = entry.getKey(); Object modelValue = entry.getValue(); if (modelValue != null) { request.setAttribute(modelName, modelValue); if (logger.isDebugEnabled()) { logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() + "] to request in view with name '" + getBeanName() + "'"); } } else { request.removeAttribute(modelName); if (logger.isDebugEnabled()) { logger.debug("Removed model object '" + modelName + "' from request in view with name '" + getBeanName() + "'"); } } } } /** InternalResourceView.java(JstlView.java) */ protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response) throws Exception { String path = getUrl(); if (this.preventDispatchLoop) { String uri = request.getRequestURI(); if (path.startsWith("/") ? uri.equals(path) : uri.equals(StringUtils.applyRelativePath(uri, path))) { throw new ServletException("Circular view path [" + path + "]: would dispatch back " + "to the current handler URL [" + uri + "] again. Check your ViewResolver setup! " + "(Hint: This may be the result of an unspecified view, due to default view name generation.)"); } } return path; } protected RequestDispatcher getRequestDispatcher(HttpServletRequest request, String path) { return request.getRequestDispatcher(path); }

    参考

    http://jinnianshilongnian.iteye.com/blog/1594806

    相关资源:看透springMvc源代码分析与实践.pdf
    转载请注明原文地址: https://ju.6miu.com/read-968331.html

    最新回复(0)