Spring技术内幕4——springmvc组件的初始化以及http请求映射(二)
2017-07-21 17:56
260 查看
我们接着上篇继续:
Spring技术内幕4——springmvc组件的初始化以及http请求映射(一)
https://my.oschina.net/guanhe/blog/1477311
这里我们进行初始化相关的HandlerMapping,为了保证我们肯定有相关的HandlerMapping处理器,这里设置了一个默认的getDefaultStrategies,
当然我们也可以自己设置相关的HandMapping,比如在我们的Spring-.xml文件中我们就可以直接设置:
使用RequestMappingHandlerMapping这个HandlerMapping,如果使用RequestMappingHandlerMapping这个HanderMapping的话,此处略有不同,使用自定义的HanderMappping,会在Ioc容器初始化的时候就直接创建这个Bean,会将Controller中的RequestMapping的值和相关处理方法保存成一个Map存到RequestMappingHandlerMapping中去,后面详细说明,我们继续这边的getDefaultStrategies方法:
其实这里没有什么内容,就是从Spring的配置文件中获取默认的HandMapping的过程:
主要是这两个HandMapping类,
其中使用AutowireCapableBeanFactory来获取创建Bean对象:
我们这里看下DefaultAnnotationHandlerMapping的继承关系,可以看见是实现了ApplicationContextAware接口的,我们知道实现了此接口在初始化的时候,会调用setApplicationContext方法,我们继续看在ApplicationObjectSupport中的setApplicationContext方法又会调用子类的initApplicationContext方法,
最终调用的便是DefaultAnnotationHandlerMapping中的:
这里便是获取RequestMapping中的ur的地方了。接下来的操作便是将url和相关的处理handler结合起来了,这部分大家可以跟下去看,主要是这个方法,此处不多讲:
好了,目前为止,url及相关的处理Handler对象(controller)的关系建立起来了,接下来便是一个http请求过来的时候,如何匹配相关的请求的过程了。
其中便是调用mappedHandler = getHandler(processedRequest, false);进行url匹配
此处我们可以看到用了之前我们存放的默认的两个HandMapping,调用他们的getHandler来获取相关的HandlerExecutionChain,最终调用的方法是AbstracthandlerMapping中的:
AbstractUrlHandlerMapping中的:
以及
进行最终的匹配。
此处总结:暂时缺失,后期补齐
Spring技术内幕4——springmvc组件的初始化以及http请求映射(一)
https://my.oschina.net/guanhe/blog/1477311
/** * Initialize the HandlerMappings used by this class. * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace, * we default to BeanNameUrlHandlerMapping. */ private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); // We keep HandlerMappings in sorted order. OrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); } } }
这里我们进行初始化相关的HandlerMapping,为了保证我们肯定有相关的HandlerMapping处理器,这里设置了一个默认的getDefaultStrategies,
当然我们也可以自己设置相关的HandMapping,比如在我们的Spring-.xml文件中我们就可以直接设置:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
使用RequestMappingHandlerMapping这个HandlerMapping,如果使用RequestMappingHandlerMapping这个HanderMapping的话,此处略有不同,使用自定义的HanderMappping,会在Ioc容器初始化的时候就直接创建这个Bean,会将Controller中的RequestMapping的值和相关处理方法保存成一个Map存到RequestMappingHandlerMapping中去,后面详细说明,我们继续这边的getDefaultStrategies方法:
/** * Create a List of default strategy objects for the given strategy interface. * <p>The default implementation uses the "DispatcherServlet.properties" file (in the same * package as the DispatcherServlet class) to determine the class names. It instantiates * the strategy objects through the context's BeanFactory. * @param context the current WebApplicationContext * @param strategyInterface the strategy interface * @return the List of corresponding strategy objects */ @SuppressWarnings("unchecked") protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { String key = strategyInterface.getName(); String value = defaultStrategies.getProperty(key); if (value != null) { String[] classNames = StringUtils.commaDelimitedListToStringArray(value); List<T> strategies = new ArrayList<T>(classNames.length); for (String className : classNames) { try { Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); Object strategy = createDefaultStrategy(context, clazz); strategies.add((T) strategy); } catch (ClassNotFoundException ex) { throw new BeanInitializationException( "Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", ex); } catch (LinkageError err) { throw new BeanInitializationException( "Error loading DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]: problem with class file or dependent class", err); } } return strategies; } else { return new LinkedList<T>(); } }
其实这里没有什么内容,就是从Spring的配置文件中获取默认的HandMapping的过程:
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
主要是这两个HandMapping类,
其中使用AutowireCapableBeanFactory来获取创建Bean对象:
/** * Create a default strategy. * <p>The default implementation uses {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean}. * @param context the current WebApplicationContext * @param clazz the strategy implementation class to instantiate * @return the fully configured strategy instance * @see org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory() * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean */ protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) { return context.getAutowireCapableBeanFactory().createBean(clazz); }
我们这里看下DefaultAnnotationHandlerMapping的继承关系,可以看见是实现了ApplicationContextAware接口的,我们知道实现了此接口在初始化的时候,会调用setApplicationContext方法,我们继续看在ApplicationObjectSupport中的setApplicationContext方法又会调用子类的initApplicationContext方法,
最终调用的便是DefaultAnnotationHandlerMapping中的:
/** * Checks for presence of the {@link org.springframework.web.bind.annotation.RequestMapping} * annotation on the handler class and on any of its methods. */ @Override protected String[] determineUrlsForHandler(String beanName) { ApplicationContext context = getApplicationContext(); Class<?> handlerType = context.getType(beanName); RequestMapping mapping = context.findAnnotationOnBean(beanName, RequestMapping.class); if (mapping != null) { // @RequestMapping found at type level this.cachedMappings.put(handlerType, mapping); Set<String> urls = new LinkedHashSet<String>(); String[] typeLevelPatterns = mapping.value(); if (typeLevelPatterns.length > 0) { // @RequestMapping specifies paths at type level String[] methodLevelPatterns = determineUrlsForHandlerMethods(handlerType, true); for (String typeLevelPattern : typeLevelPatterns) { if (!typeLevelPattern.startsWith("/")) { typeLevelPattern = "/" + typeLevelPattern; } boolean hasEmptyMethodLevelMappings = false; for (String methodLevelPattern : methodLevelPatterns) { if (methodLevelPattern == null) { hasEmptyMethodLevelMappings = true; } else { String combinedPattern = getPathMatcher().combine(typeLevelPattern, methodLevelPattern); addUrlsForPath(urls, combinedPattern); } } if (hasEmptyMethodLevelMappings || org.springframework.web.servlet.mvc.Controller.class.isAssignableFrom(handlerType)) { addUrlsForPath(urls, typeLevelPattern); } } return StringUtils.toStringArray(urls); } else { // actual paths specified by @RequestMapping at method level return determineUrlsForHandlerMethods(handlerType, false); } } else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) { // @RequestMapping to be introspected at method level return determineUrlsForHandlerMethods(handlerType, false); } else { return null; } }
这里便是获取RequestMapping中的ur的地方了。接下来的操作便是将url和相关的处理handler结合起来了,这部分大家可以跟下去看,主要是这个方法,此处不多讲:
/** * Register the specified handler for the given URL path. * @param urlPath the URL the bean should be mapped to * @param handler the handler instance or handler bean name String * (a bean name will automatically be resolved into the corresponding handler bean) * @throws BeansException if the handler couldn't be registered * @throws IllegalStateException if there is a conflicting handler registered */ protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { Assert.notNull(urlPath, "URL path must not be null"); Assert.notNull(handler, "Handler object must not be null"); Object resolvedHandler = handler; // Eagerly resolve handler if referencing singleton via name. if (!this.lazyInitHandlers && handler instanceof String) { String handlerName = (String) handler; if (getApplicationContext().isSingleton(handlerName)) { resolvedHandler = getApplicationContext().getBean(handlerName); } } Object mappedHandler = this.handlerMap.get(urlPath); if (mappedHandler != null) { if (mappedHandler != resolvedHandler) { throw new IllegalStateException( "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath + "]: There is already " + getHandlerDescription(mappedHandler) + " mapped."); } } else { if (urlPath.equals("/")) { if (logger.isInfoEnabled()) { logger.info("Root mapping to " + getHandlerDescription(handler)); } setRootHandler(resolvedHandler); } else if (urlPath.equals("/*")) { if (logger.isInfoEnabled()) { logger.info("Default mapping to " + getHandlerDescription(handler)); } setDefaultHandler(resolvedHandler); } else { this.handlerMap.put(urlPath, resolvedHandler); if (logger.isInfoEnabled()) { logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler)); } } } }
好了,目前为止,url及相关的处理Handler对象(controller)的关系建立起来了,接下来便是一个http请求过来的时候,如何匹配相关的请求的过程了。
Http请求匹配:
我们知道一个http请求过来的时候,会调用Servlet的service方法,我们之前看过DispatchServlet的继承关系,我们知道,最后其中调用的是DispatchServlet中的doDispatch方法:/** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
其中便是调用mappedHandler = getHandler(processedRequest, false);进行url匹配
/** * Return the HandlerExecutionChain for this request. Try all handler mappings in order. * @param request current HTTP request * @param cache whether to cache the HandlerExecutionChain in a request attribute * @return the HandlerExecutionChain, or {@code null} if no handler could be found * @deprecated as of Spring 3.0.4, in favor of {@link #getHandler(javax.servlet.http.HttpServletRequest)}, * with this method's cache attribute now effectively getting ignored */ @Deprecated protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception { return getHandler(request); } /** * Return the HandlerExecutionChain for this request. * <p>Tries all handler mappings in order. * @param request current HTTP request * @return the HandlerExecutionChain, or {@code null} if no handler could be found */ protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
此处我们可以看到用了之前我们存放的默认的两个HandMapping,调用他们的getHandler来获取相关的HandlerExecutionChain,最终调用的方法是AbstracthandlerMapping中的:
/** * Look up a handler for the given request, falling back to the default * handler if no specific one is found. * @param request current HTTP request * @return the corresponding handler instance, or the default handler * @see #getHandlerInternal */ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } return getHandlerExecutionChain(handler, request); }
AbstractUrlHandlerMapping中的:
/** * Look up a handler for the URL path of the given request. * @param request current HTTP request * @return the handler instance, or {@code null} if none found */ @Override protected Object getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); Object handler = lookupHandler(lookupPath, request); if (handler == null) { // We need to care for the default handler directly, since we need to // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well. Object rawHandler = null; if ("/".equals(lookupPath)) { rawHandler = getRootHandler(); } if (rawHandler == null) { rawHandler = getDefaultHandler(); } if (rawHandler != null) { // Bean name or resolved handler? if (rawHandler instanceof String) { String handlerName = (String) rawHandler; rawHandler = getApplicationContext().getBean(handlerName); } validateHandler(rawHandler, request); handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null); } } if (handler != null && logger.isDebugEnabled()) { logger.debug("Mapping [" + lookupPath + "] to " + handler); } else if (handler == null && logger.isTraceEnabled()) { logger.trace("No handler mapping found for [" + lookupPath + "]"); } return handler; }
以及
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // Direct match? Object handler = this.handlerMap.get(urlPath); if (handler != null) { // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); return buildPathExposingHandler(handler, urlPath, urlPath, null); } // Pattern match? List<String> matchingPatterns = new ArrayList<String>(); for (String registeredPattern : this.handlerMap.keySet()) { if (getPathMatcher().match(registeredPattern, urlPath)) { matchingPatterns.add(registeredPattern); } } String bestPatternMatch = null; Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath); if (!matchingPatterns.isEmpty()) { Collections.sort(matchingPatterns, patternComparator); if (logger.isDebugEnabled()) { logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns); } bestPatternMatch = matchingPatterns.get(0); } if (bestPatternMatch != null) { handler = this.handlerMap.get(bestPatternMatch); // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath); // There might be multiple 'best patterns', let's make sure we have the correct URI template variables // for all of them Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>(); for (String matchingPattern : matchingPatterns) { if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) { Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath); Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars); uriTemplateVariables.putAll(decodedVars); } } if (logger.isDebugEnabled()) { logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables); } return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables); } // No handler found... return null; }
进行最终的匹配。
此处总结:暂时缺失,后期补齐
相关文章推荐
- Spring技术内幕4——springmvc组件的初始化以及http请求映射(一)
- spring技术内幕9-AOP通知以及编程式AOP
- Spring技术内幕之IOC容器的实现(01)-IOC容器初始化过程
- DFSClient技术内幕 (DFSClient介绍以及其初始化)
- Spring技术内幕之数据库操作组件的实现(02)-ORM的设计与实现
- spring技术内幕笔记:IoC容器的初始化过程(3)- BeanDefinition的注册
- spring 技术内幕--IOC初始化过程深入之BeanDefinition的定位
- spring 技术内幕--IOC初始化之BeanDefinition的在IOC容器中的注册
- SPRING技术内幕-笔记(九)SpringMVC视图的呈现
- spring技术内幕笔记:ApplicationContext和Bean的初始化及销毁
- Spring技术内幕之数据库操作组件的实现(01)-JDBC的设计与实现
- SpringWeb MVC处理请求的流程:(处理器映射器、处理器适配器、视图解析器称为springmvc的三大组件)
- spring技术内幕笔记:IoC容器初始化过程(1)- Resource定位
- SPRING技术内幕-笔记(八)SpringMVC的设计与实现
- spring技术内幕笔记:IoC容器初始化过程(2)- BeanDefinition的载入
- JavaEE_Mybatis_SpringMVC_Spring_lesson3_注解处理器映射器与适配器以及处理器(Controller)
- SPRING技术内幕-笔记(七)WEB环境中的springMVC
- spring 技术内幕--IOC初始化过程深入之BeanDefinition的载入和解析1
- Spring学习10-SpringMVC原理及核心组件1
- [置顶] dubbo2.5-spring4-mybastis3.2-springmvc4-mongodb3.4-redis3.2整合(二)之 JDBC连接池、监控组件 Druid