返回介绍

11.4.2 根据 request 信息寻找对应的 Handler

发布于 2025-04-22 22:09:17 字数 8516 浏览 0 评论 0 收藏

在 Spring 中最简单的映射处理器配置如下:

<bean id="simpleUrlMapping"

 class="org.Springframework.web.servlet.handler.SimpleUrlHandlerMapping">

  <property name="mappings">

  <props>

    <prop key="/userlist.htm">userController</prop>

  </props>

 </property>

</bean>

在 Spring 加载的过程中,Spring 会将类型为 SimpleUrlHandlerMapping 的实例加载到 this.handlerMappings 中,按照常理推断,根据 request 提取对应的 Handler,无非就是提取当前实例中的 userController,但是 userController 为继承自 AbstractController 类型实例,与 Handler ExecutionChain 并无任何关联,那么这一步是如何封装的呢?

protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache)

throws Exception {

 return getHandler(request);

}

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;

}

在之前的内容我们提过,在系统启动时 Spring 会将所有的映射类型的 bean 注册到 this.handlerMappings 变量中,所以此函数的目的就是遍历所有的 HandlerMapping,并调用其 getHandler 方法进行封装处理。以 SimpleUrlHandlerMapping 为例查看其 getHandler 方法如下:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws

Exception {

 //根据 request 获取对应的 handler

  Object handler = getHandlerInternal(request);

  if (handler == null) {

  //如果没有对应 request 的 handler 则使用默认的 handler

   handler = getDefaultHandler();

 }

//如果也没有提供默认的 handler 则无法继续处理返回 null

  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);

}

函数中首先会使用 getHandlerInternal 方法根据 request 信息获取对应的 Handler,如果以 SimpleUrlHandlerMapping 为例分析,那么我们推断此步骤提供的功能很可能就是根据 URL 找到匹配的 Controller 并返回,当然如果没有找到对应的 Controller 处理器那么程序会尝试去查找配置中的默认处理器,当然,当查找的 controller 为 String 类型时,那就意味着返回的是配置的 bean 名称,需要根据 bean 名称查找对应的 bean,最后,还要通过 getHandlerExecutionChain 方法对返回的 Handler 进行封装,以保证满足返回类型的匹配。下面详细分析这个过程。

1.根据 request 查找对应的 Handler

首先从根据 request 查找对应的 Handler 开始分析。

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {

 //截取用于匹配的 url 有效路径

   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);

 //根据路径寻找 Handler

   Object handler = lookupHandler(lookupPath, request);

   if (handler == null) {

    Object rawHandler = null;

    if ("/".equals(lookupPath)) {

    //如果请求的路径仅仅是”/”,那么使用 RootHandler 进行处理

     rawHandler = getRootHandler();

   }

    if (rawHandler == null) {

    //无法找到 handler 则使用默认 handler

     rawHandler = getDefaultHandler();

   }

    if (rawHandler != null) {

    //根据 beanName 获取对应的 bean

     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 {

 //直接匹配情况的处理

   Object handler = this.handlerMap.get(urlPath);

   if (handler != null) {

    // Bean name

    if (handler instanceof String) {

     String handlerName = (String) handler;

     handler = getApplicationContext().getBean(handlerName);

   }

    validateHandler(handler, request);

    return buildPathExposingHandler(handler, urlPath, urlPath, null);

  }

  // 通配符匹配的处理

   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) {

    uriTemplateVariables

    .putAll(getPathMatcher().extractUriTemplateVariables

     (matchingPattern, urlPath));

   }

  }

   if (logger.isDebugEnabled()) {

    logger.debug("URI Template variables for request [" + urlPath + "] are

    " + uriTemplateVariables);

  }

   returnbuildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping,

  uriTemplateVariables);

 }

  // No handler found...

  return null;

}

根据 URL 获取对应 Handler 的匹配规则代码实现起来虽然很长,但是并不难理解,考虑了直接匹配与通配符两种情况。其中要提及的是 buildPathExposingHandler 函数,它将 Handler 封装成了 HandlerExecutionChain 类型。

protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,

String pathWithinMapping, Map<String, String> uriTemplateVariables) {

  HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);

  chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern,

 pathWithinMapping));

  if (!CollectionUtils.isEmpty(uriTemplateVariables)) {

   chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor (uri

  TemplateVariables));

 }

  return chain;

}

在函数中我们看到了通过将 Handler 以参数形式传入,并构建 HandlerExecutionChain 类型实例,加入了两个拦截器。此时我们似乎已经了解了 Spring 这样大番周折的目的。链处理机制,是 Spring 中非常常用的处理方式,是 AOP 中的重要组成部分,可以方便地对目标对象进行扩展及拦截,这是非常优秀的设计。

2.加入拦截器到执行链

getHandlerExecutionChain 函数最主要的目的是将配置中的对应拦截器加入到执行链中,以保证这些拦截器可以有效地作用于目标对象。

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest

request) {

  HandlerExecutionChain chain =

  (handler instanceof HandlerExecutionChain) ?

  (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);

 chain.addInterceptors(getAdaptedInterceptors());

  String lookupPath = urlPathHelper.getLookupPathForRequest(request);

  for (MappedInterceptor mappedInterceptor : mappedInterceptors) {

   if (mappedInterceptor.matches(lookupPath, pathMatcher)) {

   chain.addInterceptor(mappedInterceptor.getInterceptor());

  }

 }

  return chain;

}

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。