zoukankan      html  css  js  c++  java
  • 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二)

     

    参考:

    http://www.cnblogs.com/leftthen/p/5207787.html

    http://www.cnblogs.com/leftthen/p/5208169.html

    http://www.cnblogs.com/leftthen/p/5208376.html

    http://www.cnblogs.com/leftthen/p/5208404.html

     

     

     

     

    HandlerMapping - SimpleUrlHandlerMapping初始化

    摘要:

    SimpleUrlHandlerMapping只是参与Handler的注册,请求映射时由AbstractUrlHandlerMapping搞定.

    初始化时,通过setMappings(Properties mappings)或者setUrlMap(Map<String, ?> urlMap)设置映射关系,然后通过WebApplicationObjectSupport的initApplicationContext调用registerHandlers进行注册.

    覆写initApplicationContext方法时,先调用父类实现,然后才调用registerHandlers进行注册.其中最终的注册registerHandler实现是由AbstractUrlHandlerMapping实现的.

    父类AbstractHandlerMapping继承了WebApplicationObjectSupport,所以SimpleUrlHandlerMapping可以通过覆写initApplicationContext注册Handler.

    注册Handler前,不忘靠AbstractHandlerMapping来初始化拦截器.

    // SimpleUrlHandlerMapping

    复制代码
    1     /**
    2      * Calls the {@link #registerHandlers} method in addition to the
    3      * superclass's initialization.
    4      */
    5     @Override
    6     public void initApplicationContext() throws BeansException {
    7         super.initApplicationContext();
    8         registerHandlers(this.urlMap);
    9     }
    复制代码

    initApplicationContext主要是进行拦截器的初始化.

      extendInterceptors是留给子类用的扩展接口,暂时没有使用

      detectMappedInterceptors是通过BeanFactoryUtils扫描应用下的全部MappedInterceptor类

      initInterceptors初始化特定的拦截器,检查MappedInterceptor,在需要时适配adaptor HandlerInterceptor

    // AbstractHandlerMapping

    复制代码
     1     /**
     2      * Initializes the interceptors.
     3      * @see #extendInterceptors(java.util.List)
     4      * @see #initInterceptors()
     5      */
     6     @Override
     7     protected void initApplicationContext() throws BeansException {
     8         extendInterceptors(this.interceptors);
     9         detectMappedInterceptors(this.mappedInterceptors);
    10         initInterceptors();
    11     }
    复制代码

    // AbstractHandlerMapping

    复制代码
     1     /**
     2      * Extension hook that subclasses can override to register additional interceptors,
     3      * given the configured interceptors (see {@link #setInterceptors}).
     4      * <p>Will be invoked before {@link #initInterceptors()} adapts the specified
     5      * interceptors into {@link HandlerInterceptor} instances.
     6      * <p>The default implementation is empty.
     7      * @param interceptors the configured interceptor List (never {@code null}),
     8      * allowing to add further interceptors before as well as after the existing
     9      * interceptors
    10      */
    11     protected void extendInterceptors(List<Object> interceptors) {
    12     }
    复制代码

    springmvc中经常使用BeanFactoryUtils扫描应用下的类来进行初始化.

    // AbstractHandlerMapping

    复制代码
     1     /**
     2      * Detects beans of type {@link MappedInterceptor} and adds them to the list of mapped interceptors.
     3      * This is done in addition to any {@link MappedInterceptor}s that may have been provided via
     4      * {@link #setInterceptors(Object[])}. Subclasses can override this method to change that.
     5      *
     6      * @param mappedInterceptors an empty list to add MappedInterceptor types to
     7      */
     8     protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {
     9         mappedInterceptors.addAll(
    10                 BeanFactoryUtils.beansOfTypeIncludingAncestors(
    11                         getApplicationContext(),MappedInterceptor.class, true, false).values());
    12     }
    复制代码

    // AbstractHandlerMapping

    复制代码
     1     /**
     2      * Initialize the specified interceptors, checking for {@link MappedInterceptor}s and adapting
     3      * HandlerInterceptors where necessary.
     4      * @see #setInterceptors
     5      * @see #adaptInterceptor
     6      */
     7     protected void initInterceptors() {
     8         if (!this.interceptors.isEmpty()) {
     9             for (int i = 0; i < this.interceptors.size(); i++) {
    10                 Object interceptor = this.interceptors.get(i);
    11                 if (interceptor == null) {
    12                     throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
    13                 }
    14                 if (interceptor instanceof MappedInterceptor) {
    15                     mappedInterceptors.add((MappedInterceptor) interceptor);
    16                 }
    17                 else {
    18                     adaptedInterceptors.add(adaptInterceptor(interceptor));
    19                 }
    20             }
    21         }
    22     }
    复制代码

    适配HandlerInterceptor和WebRequestHandlerInterceptorAdapter(什么是WebRequestHandlerInterceptorAdapter,晚点再说吧,具体看到时候拦截器部分的分析)

    // AbstractHandlerMapping

    复制代码
     1     /**
     2      * Adapt the given interceptor object to the HandlerInterceptor interface.
     3      * <p>Supported interceptor types are HandlerInterceptor and WebRequestInterceptor.
     4      * Each given WebRequestInterceptor will be wrapped in a WebRequestHandlerInterceptorAdapter.
     5      * Can be overridden in subclasses.
     6      * @param interceptor the specified interceptor object
     7      * @return the interceptor wrapped as HandlerInterceptor
     8      * @see org.springframework.web.servlet.HandlerInterceptor
     9      * @see org.springframework.web.context.request.WebRequestInterceptor
    10      * @see WebRequestHandlerInterceptorAdapter
    11      */
    12     protected HandlerInterceptor adaptInterceptor(Object interceptor) {
    13         if (interceptor instanceof HandlerInterceptor) {
    14             return (HandlerInterceptor) interceptor;
    15         }
    16         else if (interceptor instanceof WebRequestInterceptor) {
    17             return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
    18         }
    19         else {
    20             throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
    21         }
    22     }
    复制代码

    这才到SimpleUrlHandlerMapping干活的地方,迭代urlMap调用AbstractUrlHandlerMapping的registerHandler进行注册

    (保障url以"/"开头就不多说了)

    // SimpleUrlHandlerMapping

    复制代码
     1     /**
     2      * Register all handlers specified in the URL map for the corresponding paths.
     3      * @param urlMap Map with URL paths as keys and handler beans or bean names as values
     4      * @throws BeansException if a handler couldn't be registered
     5      * @throws IllegalStateException if there is a conflicting handler registered
     6      */
     7     protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
     8         if (urlMap.isEmpty()) {
     9             logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
    10         }
    11         else {
    12             for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
    13                 String url = entry.getKey();
    14                 Object handler = entry.getValue();
    15                 // Prepend with slash if not already present.
    16                 if (!url.startsWith("/")) {
    17                     url = "/" + url;
    18                 }
    19                 // Remove whitespace from handler bean name.
    20                 if (handler instanceof String) {
    21                     handler = ((String) handler).trim();
    22                 }
    23                 registerHandler(url, handler);
    24             }
    25         }
    26     }
    复制代码

    // AbstractUrlHandlerMapping

    复制代码
     1 /**
     2      * Register the specified handler for the given URL path.
     3      * @param urlPath the URL the bean should be mapped to
     4      * @param handler the handler instance or handler bean name String
     5      * (a bean name will automatically be resolved into the corresponding handler bean)
     6      * @throws BeansException if the handler couldn't be registered
     7      * @throws IllegalStateException if there is a conflicting handler registered
     8      */
     9     protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
    10         Assert.notNull(urlPath, "URL path must not be null");
    11         Assert.notNull(handler, "Handler object must not be null");
    12         Object resolvedHandler = handler;
    13 
    14         // Eagerly resolve handler if referencing singleton via name.不是单例同时不是懒加载
    15         if (!this.lazyInitHandlers && handler instanceof String) {
    16             String handlerName = (String) handler;
    17             if (getApplicationContext().isSingleton(handlerName)) {
    18                 resolvedHandler = getApplicationContext().getBean(handlerName);
    19             }
    20         }
    21 
    22         Object mappedHandler = this.handlerMap.get(urlPath);// 获取之前已经匹配的Handler
    23         if (mappedHandler != null) {
    24             if (mappedHandler != resolvedHandler) {// 如果新匹配得到的跟之前已解析到的handler不一致,则抛异常
    25                 throw new IllegalStateException(
    26                         "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
    27                         "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
    28             }
    29         }
    30         else {
    31             if (urlPath.equals("/")) {// 设置rootHandler
    32                 if (logger.isInfoEnabled()) {
    33                     logger.info("Root mapping to " + getHandlerDescription(handler));
    34                 }
    35                 setRootHandler(resolvedHandler);
    36             }
    37             else if (urlPath.equals("/*")) {// 设置默认的defaultHandler
    38                 if (logger.isInfoEnabled()) {
    39                     logger.info("Default mapping to " + getHandlerDescription(handler));
    40                 }
    41                 setDefaultHandler(resolvedHandler);
    42             }
    43             else {// 最后才是普通handler的设置
    44                 this.handlerMap.put(urlPath, resolvedHandler);
    45                 if (logger.isInfoEnabled()) {
    46                     logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
    47                 }
    48             }
    49         }
    50     }
    复制代码
     
     
     
     
     
     
     
     

    HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化

    AbstractDetectingUrlHandlerMapping是通过扫描方式注册Handler,收到请求时由AbstractUrlHandlerMapping的getHandlerInternal进行分发.

    共有5个子类,一个抽象类.

    与SimpleUrlHandlerMapping类似,通过覆写initApplicationContext,然后调用detectHandlers进行初始化.

    detectHandlers通过BeanFactoryUtils扫描应用下的Object,然后预留determineUrlsForHandler给子类根据Handler生成对应的url.

    注册使用的registerHandler依然由AbstractUrlHandlerMapping提供.

    // AbstractDetectingUrlHandlerMapping

    复制代码
    1     /**
    2      * Calls the {@link #detectHandlers()} method in addition to the
    3      * superclass's initialization.
    4      */
    5     @Override
    6     public void initApplicationContext() throws ApplicationContextException {
    7         super.initApplicationContext();
    8         detectHandlers();
    9     }
    复制代码

    这边一样是调用AbstractHandlerMapping的initApplicationContext初始化拦截器.

    主角上场,detectHandlers,扫描Handlers

    // AbstractDetectingUrlHandlerMapping

    复制代码
     1     /**
     2      * Register all handlers found in the current ApplicationContext.
     3      * <p>The actual URL determination for a handler is up to the concrete
     4      * {@link #determineUrlsForHandler(String)} implementation. A bean for
     5      * which no such URLs could be determined is simply not considered a handler.
     6      * @throws org.springframework.beans.BeansException if the handler couldn't be registered
     7      * @see #determineUrlsForHandler(String)
     8      */
     9     protected void detectHandlers() throws BeansException {
    10         if (logger.isDebugEnabled()) {
    11             logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
    12         }
    13         String[] beanNames = (this.detectHandlersInAncestorContexts ?
    14                 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
    15                 getApplicationContext().getBeanNamesForType(Object.class));
    16 
    17         // Take any bean name that we can determine URLs for.
    18         for (String beanName : beanNames) {
    19             String[] urls = determineUrlsForHandler(beanName);
    20             if (!ObjectUtils.isEmpty(urls)) {
    21                 // URL paths found: Let's consider it a handler.
    22                 registerHandler(urls, beanName);
    23             }
    24             else {
    25                 if (logger.isDebugEnabled()) {
    26                     logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
    27                 }
    28             }
    29         }
    30     }
    复制代码

    这边预留的模板方法定义如下:

    复制代码
    1     /**
    2      * Determine the URLs for the given handler bean.
    3      * @param beanName the name of the candidate bean
    4      * @return the URLs determined for the bean,
    5      * or {@code null} or an empty array if none
    6      */
    7     protected abstract String[] determineUrlsForHandler(String beanName);
    复制代码

    我们再来看看模板方法在BeanNameUrlHandlerMapping和AbstractControllerUrlHandlerMapping中的实现吧.

    BeanNameUrlHandlerMapping非常简单,就实现了determineUrlsForHandler.

    其中的alias应该是应该就是通过beanName在配置文件中配置的.

    // BeanNameUrlHandlerMapping

    复制代码
     1     /**
     2      * Checks name and aliases of the given bean for URLs, starting with "/".
     3      */
     4     @Override
     5     protected String[] determineUrlsForHandler(String beanName) {
     6         List<String> urls = new ArrayList<String>();
     7         if (beanName.startsWith("/")) {
     8             urls.add(beanName);
     9         }
    10         String[] aliases = getApplicationContext().getAliases(beanName);
    11         for (String alias : aliases) {
    12             if (alias.startsWith("/")) {
    13                 urls.add(alias);
    14             }
    15         }
    16         return StringUtils.toStringArray(urls);
    17     }
    复制代码

    再来看看AbstractControllerUrlHandlerMapping中的实现

      isEligibleForMapping判断controller是否被排除在外(通过包package排除或类class排除).

      buildUrlsForHandler由子类实现具体的url生成规则

      isControllerType判断是否Controller的子类

      buildUrlsForHandler预留给子类生产url的模板方法.

    // AbstractControllerUrlHandlerMapping

    复制代码
     1     /**
     2      * This implementation delegates to {@link #buildUrlsForHandler},
     3      * provided that {@link #isEligibleForMapping} returns {@code true}.
     4      */
     5     @Override
     6     protected String[] determineUrlsForHandler(String beanName) {
     7         Class beanClass = getApplicationContext().getType(beanName);
     8         if (isEligibleForMapping(beanName, beanClass)) {
     9             return buildUrlsForHandler(beanName, beanClass);
    10         }
    11         else {
    12             return null;
    13         }
    14     }
    复制代码

     // AbstractControllerUrlHandlerMapping

    复制代码
     1     /**判断controller是否被排除在外(通过包package排除或类class排除).
     2      * Determine whether the specified controller is excluded from this mapping.
     3      * @param beanName the name of the controller bean
     4      * @param beanClass the concrete class of the controller bean
     5      * @return whether the specified class is excluded
     6      * @see #setExcludedPackages
     7      * @see #setExcludedClasses
     8      */
     9     protected boolean isEligibleForMapping(String beanName, Class beanClass) {
    10         if (beanClass == null) {
    11             if (logger.isDebugEnabled()) {
    12                 logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " +
    13                         "because its bean type could not be determined");
    14             }
    15             return false;
    16         }
    17         if (this.excludedClasses.contains(beanClass)) {
    18             if (logger.isDebugEnabled()) {
    19                 logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " +
    20                         "because its bean class is explicitly excluded: " + beanClass.getName());
    21             }
    22             return false;
    23         }
    24         String beanClassName = beanClass.getName();
    25         for (String packageName : this.excludedPackages) {
    26             if (beanClassName.startsWith(packageName)) {
    27                 if (logger.isDebugEnabled()) {
    28                     logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " +
    29                             "because its bean class is defined in an excluded package: " + beanClass.getName());
    30                 }
    31                 return false;
    32             }
    33         }
    34         return isControllerType(beanClass);
    35     }
    复制代码

     // AbstractControllerUrlHandlerMapping

    复制代码
    1     /**
    2      * Determine whether the given bean class indicates a controller type
    3      * that is supported by this mapping strategy.
    4      * @param beanClass the class to introspect
    5      */
    6     protected boolean isControllerType(Class beanClass) {
    7         return this.predicate.isControllerType(beanClass);
    8     }
    复制代码

     // ControllerTypePredicate

    这边提供2个api,分别判断是Controller的子类还是MultiActionController的子类.

    复制代码
     1 /**
     2  * Internal helper class that identifies controller types.
     3  *
     4  * @author Juergen Hoeller
     5  * @since 2.5.3
     6  */
     7 class ControllerTypePredicate {
     8 
     9     public boolean isControllerType(Class beanClass) {
    10         return Controller.class.isAssignableFrom(beanClass);
    11     }
    12 
    13     public boolean isMultiActionControllerType(Class beanClass) {
    14         return MultiActionController.class.isAssignableFrom(beanClass);
    15     }
    16 
    17 }
    复制代码

    预留生成url的模板方法

     // AbstractControllerUrlHandlerMapping

    复制代码
    1     /**
    2      * Abstract template method to be implemented by subclasses.
    3      * @param beanName the name of the bean
    4      * @param beanClass the type of the bean
    5      * @return the URLs determined for the bean
    6      */
    7     protected abstract String[] buildUrlsForHandler(String beanName, Class beanClass);
    复制代码

    再来看看AbstractControllerUrlHandlerMapping的2个实现ControllerBeanNameUrlHandlerMapping和ControllerClassNameUrlHandlerMapping.

    其实这两个,很简单,一个是根据beanName来生产url,一个是根据className来生产url.

    // ControllerBeanNameUrlHandlerMapping

    复制代码
     1     @Override
     2     protected String[] buildUrlsForHandler(String beanName, Class beanClass) {
     3         List<String> urls = new ArrayList<String>();
     4         urls.add(generatePathMapping(beanName));
     5         String[] aliases = getApplicationContext().getAliases(beanName);// 也获取配置的别名
     6         for (String alias : aliases) {
     7             urls.add(generatePathMapping(alias));
     8         }
     9         return StringUtils.toStringArray(urls);
    10     }
    复制代码

    // ControllerBeanNameUrlHandlerMapping

    复制代码
     1     /**对path添加前后缀,还有/
     2      * Prepends a '/' if required and appends the URL suffix to the name.
     3      */
     4     protected String generatePathMapping(String beanName) {
     5         String name = (beanName.startsWith("/") ? beanName : "/" + beanName);
     6         StringBuilder path = new StringBuilder();
     7         if (!name.startsWith(this.urlPrefix)) {
     8             path.append(this.urlPrefix);
     9         }
    10         path.append(name);
    11         if (!name.endsWith(this.urlSuffix)) {
    12             path.append(this.urlSuffix);
    13         }
    14         return path.toString();
    15     }
    复制代码

    // ControllerClassNameUrlHandlerMapping

    直接委托给generatePathMappings实现

    1     @Override
    2     protected String[] buildUrlsForHandler(String beanName, Class beanClass) {
    3         return generatePathMappings(beanClass);
    4     }

    // ControllerClassNameUrlHandlerMapping

      通过buildPathPrefix获取path的前缀

      通过ClassUtils获取className,如BookController(不带包名),同时使用cglib代理的问题一并解决

      根据大小写是否敏感,转换className(默认caseSensitive = false;)

      isMultiActionControllerType判断Controller是否MultiActionController的子类,就是controller是否包含多个handler

    复制代码
     1     /**
     2      * Generate the actual URL paths for the given controller class.
     3      * <p>Subclasses may choose to customize the paths that are generated
     4      * by overriding this method.
     5      * @param beanClass the controller bean class to generate a mapping for
     6      * @return the URL path mappings for the given controller
     7      */
     8     protected String[] generatePathMappings(Class beanClass) {
     9         StringBuilder pathMapping = buildPathPrefix(beanClass);
    10         String className = ClassUtils.getShortName(beanClass);
    11         String path = (className.endsWith(CONTROLLER_SUFFIX) ?
    12                 className.substring(0, className.lastIndexOf(CONTROLLER_SUFFIX)) : className);
    13         if (path.length() > 0) {
    14             if (this.caseSensitive) {
    15                 pathMapping.append(path.substring(0, 1).toLowerCase()).append(path.substring(1));
    16             }
    17             else {
    18                 pathMapping.append(path.toLowerCase());
    19             }
    20         }
    21         if (isMultiActionControllerType(beanClass)) {
    22             return new String[] {pathMapping.toString(), pathMapping.toString() + "/*"};
    23         }
    24         else {
    25             return new String[] {pathMapping.toString() + "*"};
    26         }
    27     }
    复制代码

    // ControllerClassNameUrlHandlerMapping

    复制代码
     1     /**
     2      * Build a path prefix for the given controller bean class.
     3      * @param beanClass the controller bean class to generate a mapping for
     4      * @return the path prefix, potentially including subpackage names as path elements
     5      */
     6     private StringBuilder buildPathPrefix(Class beanClass) {
     7         StringBuilder pathMapping = new StringBuilder();
     8         if (this.pathPrefix != null) {
     9             pathMapping.append(this.pathPrefix);
    10             pathMapping.append("/");
    11         }
    12         else {
    13             pathMapping.append("/");
    14         }
    15         if (this.basePackage != null) {
    16             String packageName = ClassUtils.getPackageName(beanClass);
    17             if (packageName.startsWith(this.basePackage)) {
    18                 String subPackage = packageName.substring(this.basePackage.length()).replace('.', '/');
    19                 pathMapping.append(this.caseSensitive ? subPackage : subPackage.toLowerCase());
    20                 pathMapping.append("/");
    21             }
    22         }
    23         return pathMapping;
    24     }
    复制代码

    // AbstractControllerUrlHandlerMapping

    predicate.isMultiActionControllerType具体实现看上面的ControllerTypePredicate

    复制代码
    1     /**
    2      * Determine whether the given bean class indicates a controller type
    3      * that dispatches to multiple action methods.
    4      * @param beanClass the class to introspect
    5      */
    6     protected boolean isMultiActionControllerType(Class beanClass) {
    7         return this.predicate.isMultiActionControllerType(beanClass);
    8     }
    复制代码
     
     
     
     
     
     
     
     

    HandlerMapping - AbstractUrlHandlerMapping系列request分发

    AbstractHandlerMapping实现HandlerMapping接口定的getHandler

      1. 提供getHandlerInternal模板方法给子类实现

      2. 如果没有获取Handler,则使用默认的defaultHandler

      3. 如果handler是string类型,从context获取实例

      4. 通过getHandlerExecutionChain封装handler,添加interceptor

    // AbstractHandlerMapping

    复制代码
     1     /**
     2      * Look up a handler for the given request, falling back to the default
     3      * handler if no specific one is found.
     4      * @param request current HTTP request
     5      * @return the corresponding handler instance, or the default handler
     6      * @see #getHandlerInternal
     7      */
     8     public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
     9         Object handler = getHandlerInternal(request);
    10         if (handler == null) {
    11             handler = getDefaultHandler();
    12         }
    13         if (handler == null) {
    14             return null;
    15         }
    16         // Bean name or resolved handler?
    17         if (handler instanceof String) {
    18             String handlerName = (String) handler;
    19             handler = getApplicationContext().getBean(handlerName);
    20         }
    21         return getHandlerExecutionChain(handler, request);
    22     }
    复制代码

    // AbstractHandlerMapping

    复制代码
     1     /**
     2      * Build a HandlerExecutionChain for the given handler, including applicable interceptors.
     3      * <p>The default implementation simply builds a standard HandlerExecutionChain with
     4      * the given handler, the handler mapping's common interceptors, and any {@link MappedInterceptor}s
     5      * matching to the current request URL. Subclasses may
     6      * override this in order to extend/rearrange the list of interceptors.
     7      * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a pre-built
     8      * HandlerExecutionChain. This method should handle those two cases explicitly,
     9      * either building a new HandlerExecutionChain or extending the existing chain.
    10      * <p>For simply adding an interceptor, consider calling {@code super.getHandlerExecutionChain}
    11      * and invoking {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
    12      * @param handler the resolved handler instance (never {@code null})
    13      * @param request current HTTP request
    14      * @return the HandlerExecutionChain (never {@code null})
    15      * @see #getAdaptedInterceptors()
    16      */
    17     protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    18         HandlerExecutionChain chain =
    19             (handler instanceof HandlerExecutionChain) ?
    20                 (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
    21 
    22         chain.addInterceptors(getAdaptedInterceptors());
    23 
    24         String lookupPath = urlPathHelper.getLookupPathForRequest(request);
    25         for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
    26             if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
    27                 chain.addInterceptor(mappedInterceptor.getInterceptor());
    28             }
    29         }
    30 
    31         return chain;
    32     }
    复制代码

    接下来看看AbstractUrlHandlerMapping实现的getHandlerInternal

    // AbstractUrlHandlerMapping

    复制代码
     1     /**
     2      * Look up a handler for the URL path of the given request.
     3      * @param request current HTTP request
     4      * @return the handler instance, or {@code null} if none found
     5      */
     6     @Override
     7     protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
     8         // 根据request获取url
     9         String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    10         // 根据url查找handler
    11         Object handler = lookupHandler(lookupPath, request);
    12         if (handler == null) {
    13             // 如果没有匹配到handler需要查找默认的,下面需要将PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE缓存到request
    14             // We need to care for the default handler directly, since we need to
    15             // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
    16             Object rawHandler = null;
    17             if ("/".equals(lookupPath)) {
    18                 rawHandler = getRootHandler();
    19             }
    20             if (rawHandler == null) {
    21                 rawHandler = getDefaultHandler();
    22             }
    23             if (rawHandler != null) {
    24                 // Bean name or resolved handler?
    25                 if (rawHandler instanceof String) {
    26                     String handlerName = (String) rawHandler;
    27                     rawHandler = getApplicationContext().getBean(handlerName);
    28                 }
    29                 // 预留的校验handler模板方法,没有使用
    30                 validateHandler(rawHandler, request);
    31                 // 添加expose属性到request的拦截器
    32                 handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
    33             }
    34         }
    35         if (handler != null && logger.isDebugEnabled()) {
    36             logger.debug("Mapping [" + lookupPath + "] to " + handler);
    37         }
    38         else if (handler == null && logger.isTraceEnabled()) {
    39             logger.trace("No handler mapping found for [" + lookupPath + "]");
    40         }
    41         return handler;
    42     }
    复制代码

    // AbstractUrlHandlerMapping

    复制代码
     1     /**
     2      * Look up a handler instance for the given URL path.
     3      * <p>Supports direct matches, e.g. a registered "/test" matches "/test",
     4      * and various Ant-style pattern matches, e.g. a registered "/t*" matches
     5      * both "/test" and "/team". For details, see the AntPathMatcher class.
     6      * <p>Looks for the most exact pattern, where most exact is defined as
     7      * the longest path pattern.
     8      * @param urlPath URL the bean is mapped to
     9      * @param request current HTTP request (to expose the path within the mapping to)
    10      * @return the associated handler instance, or {@code null} if not found
    11      * @see #exposePathWithinMapping
    12      * @see org.springframework.util.AntPathMatcher
    13      */
    14     protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    15         // Direct match? 直接根据url进行查找handler
    16         Object handler = this.handlerMap.get(urlPath);
    17         if (handler != null) {
    18             // Bean name or resolved handler?
    19             if (handler instanceof String) {
    20                 String handlerName = (String) handler;
    21                 handler = getApplicationContext().getBean(handlerName);
    22             }
    23             validateHandler(handler, request);
    24             return buildPathExposingHandler(handler, urlPath, urlPath, null);
    25         }
    26         // Pattern match? 通过表达式进行匹配具体通过AntPathMatcher实现,具体后面分析
    27         List<String> matchingPatterns = new ArrayList<String>();
    28         for (String registeredPattern : this.handlerMap.keySet()) {
    29             if (getPathMatcher().match(registeredPattern, urlPath)) {
    30                 matchingPatterns.add(registeredPattern);
    31             }
    32         }
    33         String bestPatternMatch = null;
    34         Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
    35         if (!matchingPatterns.isEmpty()) {
    36             Collections.sort(matchingPatterns, patternComparator);
    37             if (logger.isDebugEnabled()) {
    38                 logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
    39             }
    40             // order序号最小的优先级最高
    41             bestPatternMatch = matchingPatterns.get(0);
    42         }
    43         if (bestPatternMatch != null) {
    44             handler = this.handlerMap.get(bestPatternMatch);
    45             // Bean name or resolved handler?
    46             if (handler instanceof String) {
    47                 String handlerName = (String) handler;
    48                 handler = getApplicationContext().getBean(handlerName);
    49             }
    50             validateHandler(handler, request);
    51             String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
    52 
    53             // There might be multiple 'best patterns', let's make sure we have the correct URI template variables
    54             // for all of them
    55             Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
    56             for (String matchingPattern : matchingPatterns) {
    57                 if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
    58                     Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
    59                     Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
    60                     uriTemplateVariables.putAll(decodedVars);
    61                 }
    62             }
    63             if (logger.isDebugEnabled()) {
    64                 logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
    65             }
    66             return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
    67         }
    68         // No handler found...
    69         return null;
    70     }
    复制代码

    设计用于校验Handler,实际什么都没做,包括子类.

    复制代码
     1     /**
     2      * Validate the given handler against the current request.
     3      * <p>The default implementation is empty. Can be overridden in subclasses,
     4      * for example to enforce specific preconditions expressed in URL mappings.
     5      * @param handler the handler object to validate
     6      * @param request current HTTP request
     7      * @throws Exception if validation failed
     8      */
     9     protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {
    10     }
    复制代码

    封装handler为HandlerExecutionChain,并添加PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor拦截器.

    复制代码
     1     /**
     2      * Build a handler object for the given raw handler, exposing the actual
     3      * handler, the {@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}, as well as
     4      * the {@link #URI_TEMPLATE_VARIABLES_ATTRIBUTE} before executing the handler.
     5      * <p>The default implementation builds a {@link HandlerExecutionChain}
     6      * with a special interceptor that exposes the path attribute and uri template variables
     7      * @param rawHandler the raw handler to expose
     8      * @param pathWithinMapping the path to expose before executing the handler
     9      * @param uriTemplateVariables the URI template variables, can be {@code null} if no variables found
    10      * @return the final handler object
    11      */
    12     protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
    13             String pathWithinMapping, Map<String, String> uriTemplateVariables) {
    14 
    15         HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
    16         chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
    17         if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
    18             chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
    19         }
    20         return chain;
    21     }
    复制代码
     
     
     
     
     
     
     
     
     

    HandlerMapping - RequestMappingHandlerMapping初始化

    RequestMappingHandlerMapping ,用于注解@Controller,@RequestMapping来定义controller.

    复制代码
     1 @Controller
     2 @RequestMapping(value = "books")
     3 public class BookController {
     4 
     5     @RequestMapping(value = "/{id}")
     6     @ResponseBody
     7     public String getBook(@PathVariable("id") String id) {
     8         // ...
     9         return id;
    10     }
    11 }
    复制代码

    初始化时,3个类的大致分工如下:

      AbstractHandlerMethodMapping定义整个算法流程;

      RequestMappingInfoHandlerMapping提供匹配条件RequestMappingInfo的解析处理;

      RequestMappingHandlerMapping根据@RequestMapping注解生成 RequestMappingInfo,同时提供isHandler实现

    整个初始化工作由AbstractHandlerMethodMapping的initHandlerMethods主导.

      1. 使用BeanFactoryUtils扫描应用下的Object或者直接从容器中获取Object

      2. 迭代类,分别判断isHandler判断目标类是否Handler

        2.1 RequestMappingHandlerMapping.isHandler根据@Controller或@RequestMapping注解判断(有任意一个)

      3. 对handler解析出所有需要分发的方法detectHandlerMethods

        3.1 获取原始的Class<?>

        3.2 使用HandlerMethodSelector.selectMethods过滤具体handler method,预留getMappingForMethod模板方法给子类

          RequestMappingHandlerMapping.getMappingForMethod根据类,方法上的RequestMapping注解生成匹配条件RequestMappingInfo

        3.3 对过滤到的每个method进行注册registerHandlerMethod

          a, 使用createHandlerMethod封装处理器为HandlerMethod

          b, 判断之前是否已经匹配条件对应的处理器是否冲突(相同的匹配条件只能有一个对应的处理器)

          c, 设置匹配条件到handler method的映射关系

          d, 从匹配条件中解析出url,并注册到urlMap(url到匹配条件的映射),这边由RequestMappingInfoHandlerMapping.getMappingPathPatterns实现

      4. 对HandlerMethod进行初始化handlerMethodsInitialized,其实现在什么都没做

    在讲初始化之前,我们先来聊聊使用到的一些概念

      1. 映射关系,url到匹配条件RequestMappingInfo,匹配条件到HandlerMethod

      2. 特殊的MultiValueMap,特别在value是个List

      3. 使用到注解@Controller,@RequestMapping

      4. 封装处理器信息的HandlerMethod

      5. 封装各类匹配条件的RequestMappingInfo(诸如pattern,http method,request parameter等)

      6. RequestCondition记录匹配条件

    1. 进行request分发前,需要在初始化时准备好映射关系,这边AbstractHandlerMethodMapping中有两个属性保存了映射关系

    // AbstractHandlerMethodMapping

    1     // 匹配条件到HandlerMethod的映射
    2     private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>();
    3     // url到匹配条件的映射
    4     private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();

    2. 这边的MultiValueMap其实挺简单,就是map的值是个list

    1 public interface MultiValueMap<K, V> extends Map<K, List<V>> {
    2   // ...      
    3 }

    3. 我们再来看看这边使用到的两个注解:

    // @Controller

    复制代码
     1     // org.springframework.stereotype.Controller
     2 @Target({ElementType.TYPE})
     3 @Retention(RetentionPolicy.RUNTIME)
     4 @Documented
     5 @Component
     6 public @interface Controller {
     7 
     8     /**
     9      * The value may indicate a suggestion for a logical component name,
    10      * to be turned into a Spring bean in case of an autodetected component.
    11      * @return the suggested component name, if any
    12      */
    13     String value() default "";
    14 
    15 }
    复制代码

    // @RequestMapping

    复制代码
     1     // org.springframework.web.bind.annotation.RequestMapping
     2     @Target({ElementType.METHOD, ElementType.TYPE})
     3     @Retention(RetentionPolicy.RUNTIME)
     4     @Documented
     5     @Mapping
     6     public @interface RequestMapping {
     7 
     8         /**
     9          * url路径,如/myPath/*.do
    10          */
    11         String[] value() default {};
    12 
    13         /**
    14          * HTTP request methods 如:GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.
    15          */
    16         RequestMethod[] method() default {};
    17 
    18         /**
    19          * requeset parameter 有3种匹配方式,是否包含某个参数,参数值相等,参数值不等于某个值,如myParam!=myValue
    20          */
    21         String[] params() default {};
    22 
    23         /**
    24          * request的header
    25          */
    26         String[] headers() default {};
    27 
    28         /**
    29          * request的content type
    30          */
    31         String[] consumes() default {};
    32 
    33         /**
    34          * 返回内容的content type
    35          */
    36         String[] produces() default {};
    37 
    38     }
    39 }
    复制代码

    4. HandlerMethod封装了处理器相关的全部信息,如类Object,方法Method,BeanFactory,参数MethodParameter[],原始方法Method

    // HandlerMethod

    复制代码
     1     // org.springframework.web.method.HandlerMethod
     2     private final Object bean;// 因为final不可修改,所以下面每次需要修改信息时,都需要new一个
     3 
     4     private final Method method;
     5 
     6     private final BeanFactory beanFactory;
     7 
     8     private final MethodParameter[] parameters;
     9 
    10     private final Method bridgedMethod;
    复制代码

    5. 这边匹配条件的范型只有一个实现,RequestMappingInfo.匹配条件里记录的是RequestCondition子类,用于诸如pattern,http method,request parameter等

    // RequestMappingInfo

    复制代码
     1     // javax.servlet.http.HttpServletRequest.RequestMappingInfo
     2 public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
     3 
     4     private final PatternsRequestCondition patternsCondition;
     5 
     6     private final RequestMethodsRequestCondition methodsCondition;
     7 
     8     private final ParamsRequestCondition paramsCondition;
     9 
    10     private final HeadersRequestCondition headersCondition;
    11 
    12     private final ConsumesRequestCondition consumesCondition;
    13 
    14     private final ProducesRequestCondition producesCondition;
    15 
    16     private final RequestConditionHolder customConditionHolder;
    17     // ...
    18 
    19 }
    复制代码

    6. 最后再简单看看RequestCondition ,这边定义了3个方法

    复制代码
     1 package org.springframework.web.servlet.mvc.condition;
     2     public interface RequestCondition<T> {
     3         /**
     4          * 拼接条件
     5          */
     6         T combine(T other);
     7 
     8         /**
     9          * 查找匹配的条件,并返回
    10          */
    11         T getMatchingCondition(HttpServletRequest request);
    12 
    13         /**
    14          * 用于排序
    15          */
    16         int compareTo(T other, HttpServletRequest request);
    17     }
    复制代码

    看看继承体系吧,老套路,定义接口,然后模板方法实现主要逻辑,具体算法留给子类实现,还有正事要做,还是后期再细化吧.

    正文

    整个初始化工作由AbstractHandlerMethodMapping的initHandlerMethods主导.copy一段,省得回去比对看

      1. 使用BeanFactoryUtils扫描应用下的Object或者直接从容器中获取Object

      2. 迭代类,分别判断isHandler判断目标类是否Handler

        2.1 RequestMappingHandlerMapping.isHandler根据@Controller或@RequestMapping注解判断(有任意一个)

      3. 对handler解析出所有需要分发的方法detectHandlerMethods

        3.1 获取原始的Class<?>

        3.2 使用HandlerMethodSelector.selectMethods过滤具体handler method,预留getMappingForMethod模板方法给子类

          RequestMappingHandlerMapping.getMappingForMethod根据类,方法上的RequestMapping注解生成匹配条件RequestMappingInfo

        3.3 对过滤到的每个method进行注册registerHandlerMethod

          a, 使用createHandlerMethod封装处理器为HandlerMethod

          b, 判断之前是否已经匹配条件对应的处理器是否冲突(相同的匹配条件只能有一个对应的处理器)

          c, 设置匹配条件到handler method的映射关系

          d, 从匹配条件中解析出url,并注册到urlMap(url到匹配条件的映射),这边由RequestMappingInfoHandlerMapping.getMappingPathPatterns实现

      4. 对HandlerMethod进行初始化handlerMethodsInitialized,其实现在什么都没做

    // AbstractHandlerMethodMapping

    复制代码
     1 /** 这个方法哪来的,具体看备注的InitializingBean
     2      * Detects handler methods at initialization.
     3      */
     4     public void afterPropertiesSet() {
     5         initHandlerMethods();
     6     }
     7 
     8     /**扫描ApplicationContext中的bean,然后筛选handler method 并注册
     9      * Scan beans in the ApplicationContext, detect and register handler methods.
    10      * @see #isHandler(Class)
    11      * @see #getMappingForMethod(Method, Class)
    12      * @see #handlerMethodsInitialized(Map)
    13      */
    14     protected void initHandlerMethods() {
    15         if (logger.isDebugEnabled()) {
    16             logger.debug("Looking for request mappings in application context: " + getApplicationContext());
    17         }
    18 
    19         String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
    20                 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
    21                 getApplicationContext().getBeanNamesForType(Object.class));
    22 
    23         for (String beanName : beanNames) {
    24             if (isHandler(getApplicationContext().getType(beanName))){
    25                 detectHandlerMethods(beanName);
    26             }
    27         }
    28         handlerMethodsInitialized(getHandlerMethods());
    29     }
    复制代码

    预留给子类实现的判断handler,实际是由RequestMappingHandlerMapping实现  

    // AbstractHandlerMethodMapping

    1     /**
    2      * Whether the given type is a handler with handler methods.
    3      * @param beanType the type of the bean being checked
    4      * @return "true" if this a handler type, "false" otherwise.
    5      */
    6     protected abstract boolean isHandler(Class<?> beanType);

     // RequestMappingHandlerMapping

    这边判断的逻辑很简单,类上使用Controller或RequestMapping其中至少一个注解就可以.

    复制代码
    1     /**
    2      * {@inheritDoc}
    3      * Expects a handler to have a type-level @{@link Controller} annotation.
    4      */
    5     @Override
    6     protected boolean isHandler(Class<?> beanType) {
    7         return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
    8                 (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
    9     }
    复制代码

    // AbstractHandlerMethodMapping

    复制代码
     1     /**
     2      * Look for handler methods in a handler.
     3      * @param handler the bean name of a handler or a handler instance
     4      */
     5     protected void detectHandlerMethods(final Object handler) {
     6         Class<?> handlerType = (handler instanceof String) ?
     7                 getApplicationContext().getType((String) handler) : handler.getClass();
     8 
     9         final Class<?> userType = ClassUtils.getUserClass(handlerType);
    10 
    11         Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
    12             public boolean matches(Method method) {
    13                 return getMappingForMethod(method, userType) != null;
    14             }
    15         });
    16 
    17         for (Method method : methods) {
    18             T mapping = getMappingForMethod(method, userType);
    19             registerHandlerMethod(handler, method, mapping);
    20         }
    21     }
    复制代码

    // AbstractHandlerMethodMapping

    这边具体的实现是由RequestMappingHandlerMapping实现,根据注解生产匹配关系,这边实现类是RequestMappingInfo,就是代码有点多,慢慢看

    复制代码
    1     /** 
    2      * Provide the mapping for a handler method. A method for which no
    3      * mapping can be provided is not a handler method.
    4      * @param method the method to provide a mapping for
    5      * @param handlerType the handler type, possibly a sub-type of the method's
    6      * declaring class
    7      * @return the mapping, or {@code null} if the method is not mapped
    8      */
    9     protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
    复制代码

    // RequestMappingHandlerMapping

    复制代码
     1     /**
     2      * Uses method and type-level @{@link RequestMapping} annotations to create
     3      * the RequestMappingInfo.
     4      *
     5      * @return the created RequestMappingInfo, or {@code null} if the method
     6      * does not have a {@code @RequestMapping} annotation.
     7      *
     8      * @see #getCustomMethodCondition(Method)
     9      * @see #getCustomTypeCondition(Class)
    10      */
    11     @Override
    12     protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    13         RequestMappingInfo info = null;
    14         // 读取方法上的RequestMapping注解信息
    15         RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
    16         if (methodAnnotation != null) {
    17             // 读取自定义的条件,这边没有使用
    18             RequestCondition<?> methodCondition = getCustomMethodCondition(method);
    19             // 根据方法上的RequsetMapping注解和自定义条件,生成匹配条件.这边的匹配条件包括http method,request parameter,request header等
    20             info = createRequestMappingInfo(methodAnnotation, methodCondition);
    21             // 读取类上的RequestMapping注解信息
    22             RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
    23             if (typeAnnotation != null) {
    24                 RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
    25                 // 生成类上的匹配条件,并合并方法上的
    26                 info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
    27             }
    28         }
    29         return info;
    30     }
    复制代码

    // RequestMappingHandlerMapping

    复制代码
     1     /**
     2      * Created a RequestMappingInfo from a RequestMapping annotation.
     3      */
     4     private RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition) {
     5         String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());
     6         return new RequestMappingInfo(
     7                 new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
     8                         this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
     9                 new RequestMethodsRequestCondition(annotation.method()),
    10                 new ParamsRequestCondition(annotation.params()),
    11                 new HeadersRequestCondition(annotation.headers()),
    12                 new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
    13                 new ProducesRequestCondition(annotation.produces(), annotation.headers(), getContentNegotiationManager()),
    14                 customCondition);
    15     }
    16 
    17     /**
    18      * Resolve placeholder values in the given array of patterns.
    19      * @return a new array with updated patterns
    20      */
    21     protected String[] resolveEmbeddedValuesInPatterns(String[] patterns) {
    22         if (this.embeddedValueResolver == null) {
    23             return patterns;
    24         }
    25         else {
    26             String[] resolvedPatterns = new String[patterns.length];
    27             for (int i=0; i < patterns.length; i++) {
    28                 resolvedPatterns[i] = this.embeddedValueResolver.resolveStringValue(patterns[i]);
    29             }
    30             return resolvedPatterns;
    31         }
    32     }
    复制代码

    // AbstractHandlerMethodMapping

    复制代码
     1 /**
     2      * Register a handler method and its unique mapping.
     3      * @param handler the bean name of the handler or the handler instance
     4      * @param method the method to register
     5      * @param mapping the mapping conditions associated with the handler method
     6      * @throws IllegalStateException if another method was already registered
     7      * under the same mapping
     8      */
     9     protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    10         HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
    11         HandlerMethod oldHandlerMethod = handlerMethods.get(mapping);
    12         if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
    13             throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean()
    14                     + "' bean method 
    " + newHandlerMethod + "
    to " + mapping + ": There is already '"
    15                     + oldHandlerMethod.getBean() + "' bean method
    " + oldHandlerMethod + " mapped.");
    16         }
    17 
    18         this.handlerMethods.put(mapping, newHandlerMethod);// 匹配条件requestMappingInfo 到处理器HandlerMethod
    19         if (logger.isInfoEnabled()) {
    20             logger.info("Mapped "" + mapping + "" onto " + newHandlerMethod);
    21         }
    22 
    23         Set<String> patterns = getMappingPathPatterns(mapping);
    24         for (String pattern : patterns) {
    25             if (!getPathMatcher().isPattern(pattern)) {
    26                 this.urlMap.add(pattern, mapping);// url到匹配条件RequestMappingInfo
    27             }
    28         }
    29     }
    复制代码

    // AbstractHandlerMethodMapping

    复制代码
     1     /**
     2      * Create the HandlerMethod instance.
     3      * @param handler either a bean name or an actual handler instance
     4      * @param method the target method
     5      * @return the created HandlerMethod
     6      */
     7     protected HandlerMethod createHandlerMethod(Object handler, Method method) {
     8         HandlerMethod handlerMethod;
     9         if (handler instanceof String) {
    10             String beanName = (String) handler;
    11             handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method);
    12         }
    13         else {
    14             handlerMethod = new HandlerMethod(handler, method);
    15         }
    16         return handlerMethod;
    17     }
    复制代码

    // AbstractHandlerMethodMapping

    1     /**
    2      * Extract and return the URL paths contained in a mapping.
    3      */
    4     protected abstract Set<String> getMappingPathPatterns(T mapping);

     RequestMappingInfoHandlerMapping会实现这个模板方法

    // RequestMappingInfoHandlerMapping

    复制代码
    1     /**
    2      * Get the URL path patterns associated with this {@link RequestMappingInfo}.
    3      */
    4     @Override
    5     protected Set<String> getMappingPathPatterns(RequestMappingInfo info) {
    6         return info.getPatternsCondition().getPatterns();
    7     }
    复制代码

    备注:

    1. 这边的afterPropertiesSet是因为实现了InitializingBean接口

    // org.springframework.beans.factory.InitializingBean

    复制代码
     1 /**
     2  * Interface to be implemented by beans that need to react once all their
     3  * properties have been set by a BeanFactory: for example, to perform custom
     4  * initialization, or merely to check that all mandatory properties have been set.
     5  *
     6  * <p>An alternative to implementing InitializingBean is specifying a custom
     7  * init-method, for example in an XML bean definition.
     8  * For a list of all bean lifecycle methods, see the BeanFactory javadocs.
     9  *
    10  * @author Rod Johnson
    11  * @see BeanNameAware
    12  * @see BeanFactoryAware
    13  * @see BeanFactory
    14  * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
    15  * @see org.springframework.context.ApplicationContextAware
    16  */
    17 public interface InitializingBean {
    18 
    19     /**
    20      * Invoked by a BeanFactory after it has set all bean properties supplied
    21      * (and satisfied BeanFactoryAware and ApplicationContextAware).
    22      * <p>This method allows the bean instance to perform initialization only
    23      * possible when all bean properties have been set and to throw an
    24      * exception in the event of misconfiguration.
    25      * @throws Exception in the event of misconfiguration (such
    26      * as failure to set an essential property) or if initialization fails.
    27      */
    28     void afterPropertiesSet() throws Exception;
    29 
    30 }
    复制代码
     
     
     
     
     
     
     

    HandlerMapping - RequestMappingHandlerMapping请求分发

    AbstractHandlerMethodMapping实现接口getHandlerInternal,定义查找流程

    RequestMappingInfoHandlerMapping根据RequestMappingInfo,细化匹配条件,并在匹配不到情况下,顽强的使用RequestCondition一再尝试匹配

    虽然 RequestMappingHandlerMapping是受益方,但在这边什么都没做(就是在初始化时,根据@Controller,@RequestMapping注解生成RequestMappingInfo;并根据这两个注解判断是否目标Handler  实现isHandler)

    AbstractHandlerMethodMapping实现接口getHandlerInternal

      1. 使用UrlPathHelper查找request对应的path

      2. 查找path对应的HandlerMethod

        2.1 从urlMap中直接等值匹配查找匹配条件RequestMappingInfo

        2.2 如果等值查找到匹配条件,将其添加到match条件中

        2.3 如果没有找到匹配条件,使用所有的handlerMethod的RequestMappingInfo进行匹配

        2.4 对匹配到的Match进行排序,取出最高优先级的Match,并核对是否是唯一的最高优先级

        2.5 对匹配到条件,没有匹配到条件的两种情况,分别进行封装

      3. 封装HandlerMethod,确保bean中存的是实例

    // AbstractHandlerMethodMapping

    实现接口getHandlerInternal

    复制代码
     1 package org.springframework.web.servlet.handler
     2     // AbstractHandlerMethodMapping<T>
     3     /**
     4      * Look up a handler method for the given request.
     5      */
     6     @Override
     7     protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
     8         // 就是request对应的url
     9         String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    10         // 查找到处理器,这边的处理器会封装成HandlerMethod
    11         HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
    12         // 确保bean中存的是实例
    13         return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null;
    14     }
    复制代码

    // AbstractHandlerMethodMapping

    复制代码
    package org.springframework.web.servlet.handler;
    public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean  {
        /**
         * Look up the best-matching handler method for the current request.
         * If multiple matches are found, the best match is selected.
         * @param lookupPath mapping lookup path within the current servlet mapping
         * @param request the current request
         * @return the best-matching handler method, or {@code null} if no match
         * @see #handleMatch(Object, String, HttpServletRequest)
         * @see #handleNoMatch(Set, String, HttpServletRequest)
         */
        protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
            List<Match> matches = new ArrayList<Match>();
            // 从urlMap中直接等值匹配查找匹配条件RequestMappingInfo
            List<T> directPathMatches = this.urlMap.get(lookupPath);
            if (directPathMatches != null) {
                // 
                addMatchingMappings(directPathMatches, matches, request);
            }
    
            if (matches.isEmpty()) {
                // No choice but to go through all mappings
                // 没有匹配的情况下,遍历handlerMethods的全部匹配条件进行查找
                addMatchingMappings(this.handlerMethods.keySet(), matches, request);
            }
    
            if (!matches.isEmpty()) {
                Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
                Collections.sort(matches, comparator);
    
                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();
                        // 不能有相同的最优Match
                        throw new IllegalStateException(
                                "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +
                                m1 + ", " + m2 + "}");
                    }
                }
                // 就是往request域中缓存url中解析出来的参数,mediaType等,这边RequestMappingHandlerMapping也覆写了一下
                handleMatch(bestMatch.mapping, lookupPath, request);
                return bestMatch.handlerMethod;
            }
            else {
                // RequestMappingHandlerMapping
                return handleNoMatch(handlerMethods.keySet(), lookupPath, request);
            }
        }
    }
    复制代码

    // AbstractHandlerMethodMapping

    查找具体符合条件的RequestCondition

    复制代码
     1 package org.springframework.web.servlet.handler;
     2 public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
     3 
     4     private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
     5         for (T mapping : mappings) {
     6             T match = getMatchingMapping(mapping, request);
     7             if (match != null) {
     8                 matches.add(new Match(match, handlerMethods.get(mapping)));
     9             }
    10         }
    11     }
    复制代码

    // AbstractHandlerMethodMapping

    复制代码
    1     /** 
    2      * Check if a mapping matches the current request and return a (potentially
    3      * new) mapping with conditions relevant to the current request.
    4      * @param mapping the mapping to get a match for
    5      * @param request the current HTTP servlet request
    6      * @return the match, or {@code null} if the mapping doesn't match
    7      */
    8     protected abstract T getMatchingMapping(T mapping, HttpServletRequest request);
    复制代码

    我们来看看RequestMappingInfoHandlerMapping中的实现,从RequestMappingInfo中查找符合的RequestCondition

    // RequestMappingInfoHandlerMapping

    复制代码
     1     /**
     2      * Check if the given RequestMappingInfo matches the current request and
     3      * return a (potentially new) instance with conditions that match the
     4      * current request -- for example with a subset of URL patterns.
     5      * @return an info in case of a match; or {@code null} otherwise.
     6      */
     7     @Override
     8     protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
     9         return info.getMatchingCondition(request);
    10     }
    复制代码

    // AbstractHandlerMethodMapping

    复制代码
    1     /**
    2      * Invoked when a matching mapping is found.
    3      * @param mapping the matching mapping
    4      * @param lookupPath mapping lookup path within the current servlet mapping
    5      * @param request the current request
    6      */
    7     protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) {
    8         request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);
    9     }
    复制代码

    RequestMappingInfoHandlerMapping中又对其进行了覆写,具体是干啥用的,等看了HandlerAdaptor再说吧

    复制代码
     1     /**
     2      * Expose URI template variables, matrix variables, and producible media types in the request.
     3      * @see HandlerMapping#URI_TEMPLATE_VARIABLES_ATTRIBUTE
     4      * @see HandlerMapping#MATRIX_VARIABLES_ATTRIBUTE
     5      * @see HandlerMapping#PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE
     6      */
     7     @Override
     8     protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
     9         super.handleMatch(info, lookupPath, request);
    10 
    11         Set<String> patterns = info.getPatternsCondition().getPatterns();
    12         String bestPattern = patterns.isEmpty() ? lookupPath : patterns.iterator().next();
    13         request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
    14 
    15         Map<String, String> uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
    16         Map<String, String> decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
    17         request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);
    18 
    19         if (isMatrixVariableContentAvailable()) {
    20             request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, extractMatrixVariables(request, uriVariables));
    21         }
    22 
    23         if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
    24             Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
    25             request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
    26         }
    27     }
    复制代码
    复制代码
     1     /**
     2      * Invoked when no matching mapping is not found.
     3      * @param mappings all registered mappings
     4      * @param lookupPath mapping lookup path within the current servlet mapping
     5      * @param request the current request
     6      * @throws ServletException in case of errors
     7      */
     8     protected HandlerMethod handleNoMatch(Set<T> mappings, String lookupPath, HttpServletRequest request)
     9             throws Exception {
    10 
    11         return null;
    12     }
    复制代码

    RequestMappingInfoHandlerMapping,覆写,不死心,再匹配一次

    // RequestMappingInfoHandlerMapping

    复制代码
     1     /**
     2      * Iterate all RequestMappingInfos once again, look if any match by URL at
     3      * least and raise exceptions accordingly.
     4      * @throws HttpRequestMethodNotSupportedException if there are matches by URL
     5      * but not by HTTP method
     6      * @throws HttpMediaTypeNotAcceptableException if there are matches by URL
     7      * but not by consumable/producible media types
     8      */
     9     @Override
    10     protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos,
    11             String lookupPath, HttpServletRequest request) throws ServletException {
    12 
    13         Set<String> allowedMethods = new LinkedHashSet<String>(4);
    14 
    15         Set<RequestMappingInfo> patternMatches = new HashSet<RequestMappingInfo>();
    16         Set<RequestMappingInfo> patternAndMethodMatches = new HashSet<RequestMappingInfo>();
    17 
    18         for (RequestMappingInfo info : requestMappingInfos) {
    19             if (info.getPatternsCondition().getMatchingCondition(request) != null) {
    20                 patternMatches.add(info);
    21                 if (info.getMethodsCondition().getMatchingCondition(request) != null) {
    22                     patternAndMethodMatches.add(info);
    23                 }
    24                 else {
    25                     for (RequestMethod method : info.getMethodsCondition().getMethods()) {
    26                         allowedMethods.add(method.name());
    27                     }
    28                 }
    29             }
    30         }
    31 
    32         if (patternMatches.isEmpty()) {
    33             return null;
    34         }
    35         else if (patternAndMethodMatches.isEmpty() && !allowedMethods.isEmpty()) {
    36             throw new HttpRequestMethodNotSupportedException(request.getMethod(), allowedMethods);
    37         }
    38 
    39         Set<MediaType> consumableMediaTypes;
    40         Set<MediaType> producibleMediaTypes;
    41         Set<String> paramConditions;
    42 
    43         if (patternAndMethodMatches.isEmpty()) {
    44             consumableMediaTypes = getConsumableMediaTypes(request, patternMatches);
    45             producibleMediaTypes = getProducibleMediaTypes(request, patternMatches);
    46             paramConditions = getRequestParams(request, patternMatches);
    47         }
    48         else {
    49             consumableMediaTypes = getConsumableMediaTypes(request, patternAndMethodMatches);
    50             producibleMediaTypes = getProducibleMediaTypes(request, patternAndMethodMatches);
    51             paramConditions = getRequestParams(request, patternAndMethodMatches);
    52         }
    53 
    54         if (!consumableMediaTypes.isEmpty()) {
    55             MediaType contentType = null;
    56             if (StringUtils.hasLength(request.getContentType())) {
    57                 try {
    58                     contentType = MediaType.parseMediaType(request.getContentType());
    59                 }
    60                 catch (IllegalArgumentException ex) {
    61                     throw new HttpMediaTypeNotSupportedException(ex.getMessage());
    62                 }
    63             }
    64             throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<MediaType>(consumableMediaTypes));
    65         }
    66         else if (!producibleMediaTypes.isEmpty()) {
    67             throw new HttpMediaTypeNotAcceptableException(new ArrayList<MediaType>(producibleMediaTypes));
    68         }
    69         else if (!CollectionUtils.isEmpty(paramConditions)) {
    70             String[] params = paramConditions.toArray(new String[paramConditions.size()]);
    71             throw new UnsatisfiedServletRequestParameterException(params, request.getParameterMap());
    72         }
    73         else {
    74             return null;
    75         }
    76     }
    复制代码
     
     
  • 相关阅读:
    蒙特卡洛采样、重要性采样
    伯努利分布和高斯分布下的最大似然估计、交叉熵
    对于分类问题的神经网络最后一层的函数:sigmoid、softmax与损失函数
    android 侧滑菜单
    安卓Animation类与xml制作动画
    LeetCode题解 #3 Longest Substring Without Repeating Characters
    GY89的使用
    使用GY89的BMP180模块获取温度和压强(海拔)
    STM32与PC机串口通讯
    STM32使用无源蜂鸣器演奏歌曲
  • 原文地址:https://www.cnblogs.com/xuwc/p/9114695.html
Copyright © 2011-2022 走看看