Springmvc 工作机制源码分析

来源:互联网 发布:肖雪萍 知乎 编辑:程序博客网 时间:2024/06/04 22:08

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 />解析的BeanDefinitionParserregisterBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());// 注册<mvc:default-servlet-handler />解析的BeanDefinitionParserregisterBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());// 注册<mvc:interceptors />解析的BeanDefinitionParserregisterBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());// 注册<mvc:resources />解析的BeanDefinitionParserregisterBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());// 注册<mvc:view-controller />解析的BeanDefinitionParserregisterBeanDefinitionParser("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 RootBeanDefinitionRootBeanDefinition 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 RootBeanDefinitionRootBeanDefinition 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 RootBeanDefinitionRootBeanDefinition 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 RootBeanDefinitionRootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);csInterceptorDef.setSource(source);csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);// MappedInterceptor RootBeanDefinitionRootBeanDefinition 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 RootBeanDefinitionRootBeanDefinition 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 RootBeanDefinitionRootBeanDefinition 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 RootBeanDefinitionRootBeanDefinition 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 RootBeanDefinitionRootBeanDefinition 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 RootBeanDefinitionRootBeanDefinition 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 RootBeanDefinitionRootBeanDefinition 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 instancesfinal Map<Method, T> mappings = new IdentityHashMap<Method, T>();final Class<?> userType = ClassUtils.getUserClass(handlerType);// 查找userType中带@RequestMapping注解的methodSet<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {public boolean matches(Method method) {// 过滤带@RequestMapping注解的method,用@RequestMapping注解的属性值,new RequestMappingInfoT 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) {//创建HandlerMethodHandlerMethod 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获取RequestMappingInfoList<T> directPathMatches = this.urlMap.get(lookupPath);if (directPathMatches != null) {// 匹配request的RequestMappingInfoaddMatchingMappings(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的MatchMatch 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的handlerMethodreturn 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,获取匹配的RequestMappingInfoT 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,获取匹配的RequestMappingInfopublic 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返回结果ModelAndViewprivate ModelAndView invokeHandleMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ServletWebRequest webRequest = new ServletWebRequest(request, response);//数据绑定FactoryWebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);//缓存调用结果Model、ViewModelAndViewContainer 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,且处理返回结果到mavContainerrequestMappingMethod.invokeAndHandle(webRequest, mavContainer);if (asyncManager.isConcurrentHandlingStarted()) {return null;}// 从mavContainer获取ModelAndViewreturn getModelAndView(mavContainer, modelFactory, webRequest);}/** ServletInvocableHandlerMethod.java */public final void invokeAndHandle(ServletWebRequest webRequest,ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {// 调用HandlerMethodObject 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键值对合并到mavContainerthis.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 */// 实际调用HandlerMethodpublic 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());}// 利用反射实际调用HandlerMethodObject 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 {// 获取ReturnValueHandlerHandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");// 处理ReturnValuehandler.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为trueif (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的属性键值对合并到mavContainermavContainer.addAllAttributes(mav.getModel());}/** RequestMappingHandlerAdapter.java */// 从mavContainer提取ModelAndViewprivate 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 forwardreturn;}if (mappedHandler != null) {// 调用拦截器链afterCompletion方法mappedHandler.triggerAfterCompletion(request, response, null);}}protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {// 确定Locale语言zh_CNLocale locale = this.localeResolver.resolveLocale(request);response.setLocale(locale);View view;if (mv.isReference()) {// 根据viewName,借助viewResolver解析,获取viewview = 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确定viewView 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) {// 创建viewview = createView(viewName, locale);if (view == null && this.cacheUnresolved) {view = UNRESOLVED_VIEW;}if (view != null) {// 缓存viewthis.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:",创建RedirectViewif (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:",创建InternalResourceViewif (viewName.startsWith(FORWARD_URL_PREFIX)) {String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());return new InternalResourceView(forwardUrl);}// 直接创建Viewreturn super.createView(viewName, locale);}protected View loadView(String viewName, Locale locale) throws Exception {// 创建viewAbstractUrlBasedView view = buildView(viewName);// 初始化view beanView 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 {// 用反射实例化viewAbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());// 设置view对应的url,例如/WEB-INF/pages/index.jspview.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的AttributeexposeModelAsRequestAttributes(model, requestToExpose);// 在request属性中设置LocalizationContext键值对exposeHelpers(requestToExpose);// 确定request dispatcher的urlString dispatcherPath = prepareForRendering(requestToExpose, response);// 获取RequestDispatcherRequestDispatcher 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

0 0
原创粉丝点击