spring源码:getHandler和getHandlerAdapter

22 篇文章 0 订阅
21 篇文章 1 订阅

spring源码:getHandler和getHandlerAdapter

getHandler

准备好HandlerMapping列表后,继续DispatcherServlet的doDispatch方法 -> getHandler方法,根据当前HttpServletRequest(其实当前为其子类型RequestFacade)适配具体要调用的Controller方法和需要执行的拦截器链,如下:

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

遍历所有的初始化的HandlerMapping列表,如果匹配到就进行返回。当前只分析常用的@RequestMapping注解方式,匹配到则会调用RequestMappingHandlerMapping的实现的mapping.getHandler方法,功能如下:

  • 匹配需要调用的方法对象(HandlerMethod)
  • 如果没有获取到,赋值默认的操作器(默认为null)
  • 如果被执行的调用类型为String,则认为是BeanFactory中Bean的名称,获取返回
  • 获取当前请求的拦截器(HandlerInterceptor)执行链,和handler绑定,并且内部获取所有的拦截器,并组装HandlerExecutionChain(HandlerMethod和HandlerInterceptor调用链)
  • 如果设置了跨域,配置跨域信息并放入handler中
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 匹配需要调用的方法对象(HandlerMethod)
    Object handler = getHandlerInternal(request);
    // 如果没有获取到,赋值默认的操作器
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // 如果被执行的调用类型为String,则认为是BeanFactory中Bean的名称,获取返回
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }
    // 获取当前请求的拦截器(HandlerInterceptor)执行链
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    // 对cors跨域方式的处理
    if (hasCorsConfigurationSource(handler)) {
        CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        config = (config != null ? config.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    return executionChain;
}

getHandlerAdapter

handlerAdapters 在初始化九大组件的时候已经完成,默认配置在DispatcherServlet.properties文件中
能否适配主要取决于适配器的supports方法如何实现

默认适配器有如下三个

  • HttpRequestHandlerAdapter
  • SimplerControllerHandlerAdapter
  • RequestMappingHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
            Iterator var2 = this.handlerAdapters.iterator();

            while(var2.hasNext()) {
                HandlerAdapter adapter = (HandlerAdapter)var2.next();
                if (adapter.supports(handler)) {
                    return adapter;
                }
            }
        }

一个请求执行过程

首先找到 DispatcherServlet ,打开这个 Servlet 的继承体系结构
在这里插入图片描述
作为一个 Servlet 必然有 doGet / doPost 方法,在 HttpServletBean 中没有找到,那么继续尝试去子类中找,打开 FrameworkServlet,在这个 Servlet 中我们找到了 doGet 和 doPost 方法

protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.processRequest(request, response);
    }

    protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.processRequest(request, response);
    }

FrameworkServlet 中的 doGet / doPost 方法最终调用的都是本类的 processRequest 方法,点进去 processRequest 方法,里面有核心的业务方法 doService(request, response)

打开 doService 方法,发现该方法是一个抽象方法

protected abstract void doService(HttpServletRequest var1, HttpServletResponse var2) throws Exception;

打开 doService 方法的实现类,我们就来到了 DispatcherServlet 这个类中,它作为 FrameworkServlet 的子类,重写了 FrameworkServlet 的抽象方法 doService

打开 DispatcherServlet 的 doService 方法,里面有该 Servlet 的核心方法 doDispatch(request, response)

打开 doDispatch 方法,里面有一个 mappedHandler = getHandler(processedRequest) 方法,该方法的作用是根据请求路径获取匹配的处理器执行链

例如
浏览器发送请求 http://localhost:8080/user/1/games/dota ,就会匹配到 MvcController 这个控制器的 requestParams 方法

// 该注解是 @Controller 和 @ResponseBody 的组合注解
// @Controller:表明该类是一个 Controller ,它的底层是 @Component 注解,会将该类注入到 IOC 容器中
// @ResponseBody:将 Controller 类中方法的返回值对象通过适当的转换器转换之后,写入到 Response 对象的 body 区(响应体中)
// 通常用来返回 JSON 或者是 XML 数据
@RestController
public class MvcController {
    // 该注解等价于 @RequestMapping(value="/user/{1}/games/{dota}",method = RequestMethod.GET)
    // Rest 风格获取 1 号用户最喜欢玩的游戏
    @GetMapping(value="/user/{userId}/games/{favGame}")
    public Map<String, Object> requestParams(
            // 将路径变量中的 userId 赋值给形式参数 id
            @PathVariable("userId") Integer id,
            // 将路径变量中的 favGame 赋值给形式参数 favouriteGame
            @PathVariable("favGame") String favouriteGame) {
 
        Map map = new HashMap<String, Object>();
        map.put("id", id);
        map.put("favouriteGame", favouriteGame);
 
        return map;
    }
}

代码块一、getHandler(processedRequest)

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 1、获取 Springboot 默认为我们注入的所有 handlerMappings ,它的作用是保存 request 和 handler 的映射规则
    if (this.handlerMappings != null) {
        // 2、循环遍历所有的 handlerMappings ,
        for (HandlerMapping mapping : this.handlerMappings) {
            // 3、获取 handler ----> 详情见代码块二
            HandlerExecutionChain handler = mapping.getHandler(request);
            // 4、如果能找到合适的 handler ,将该处理器返回
            if (handler != null) {
                return handler;
            }
        }
    }
    // 5、如果没有找到合适的处理器,返回 null
    return null;
}

1、handlerMappings: Springboot 为我们默认配置的 handlerMappings 如下
在这里插入图片描述
所有的 mapping 映射关系保存在 mappingRegistry (映射注册中心) 中,具体的 @RequestMapping 注解与其处理器映射关系如下
在这里插入图片描述
3、获取 handler: 获取处理器 handler 并将其封装在处理器执行链中(HandlerExecutionChain 封装 handler 和 interceptors) ----> 详情见代码块八

代码块二、mapping.getHandler(request)中的getHandler

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 1、获取内部的处理器 ----> 详情见代码块三
    Object handler = getHandlerInternal(request);
    // 2、如果没有定义处理器,则获取默认的处理器(默认的处理器为 null,难道是需要我们自己设置一个默认的处理器吗?)
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }
    // 3、获取处理器执行链 ----> 代码块六
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
 
    if (logger.isTraceEnabled()) {
        logger.trace("Mapped to " + handler);
    }
    else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        logger.debug("Mapped to " + executionChain.getHandler());
    }
    // 4、与跨域访问有关
    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
        CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        config = (config != null ? config.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    // 5、返回处理器执行链
    return executionChain;
}

1、getHandlerInternal(request):获取内部的处理器 ----> 详情见代码块三

3、getHandlerExecutionChain:获取处理器执行链 ----> 代码块六

代码块三、getHandlerInternal

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 1、移除可生产的媒体类型属性值
    request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    try {
        // 2、调用父类的 getHandlerInternal 方法 ----> 详情见代码块四
        return super.getHandlerInternal(request);
    }
    finally {
        // 3、清除媒体类型属性
        ProducesRequestCondition.clearMediaTypesAttribute(request);
    }
}

代码块四、super.getHandlerInternal(request)中的getHandlerInternal

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 1、通过 UrlPathHelper 获取 request 请求中的请求路径(浏览器或其它客户端发送的请求路径 user/1/games/dota
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    // 2、将获取到的请求路径作为属性设置到 request 中
    request.setAttribute(LOOKUP_PATH, lookupPath);
    // 3、读锁
    this.mappingRegistry.acquireReadLock();
    try {
        // 4、获取处理器方法 ----> 详情见代码块五
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        // 5、返回最终的处理器方法(也就是哪个 Controller 中的哪个方法能处理该请求)
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        // 6、释放锁
        this.mappingRegistry.releaseReadLock();
    }
}

代码块五、寻找处理器方法:lookupHandlerMethod

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    // 1、定义一个 List 集合 matches
    List<Match> matches = new ArrayList<>();
    // 2、根据请求路径查询有没有能直接匹配上的,如果有,则将其存入 directPathMatches 集合中
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    // 3、如果直接匹配上了,则添加到 matches 集合中
    if (directPathMatches != null) {
        addMatchingMappings(directPathMatches, matches, request);
    }
    // 4、如果没有直接匹配上,则获取所有的映射,挨个匹配
    if (matches.isEmpty()) {
        // No choice but to go through all mappings...
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }
    // 5、匹配、排序、筛选出最匹配的处理方法
    if (!matches.isEmpty()) {
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            matches.sort(comparator);
            bestMatch = matches.get(0);
            if (logger.isTraceEnabled()) {
                logger.trace(matches.size() + " matching mappings: " + matches);
            }
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                String uri = request.getRequestURI();
                throw new IllegalStateException(
                        "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
            }
        }
        // 6、将获取的最佳处理方法设置为 request 的属性
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
        // 7、处理具体的匹配
        handleMatch(bestMatch.mapping, lookupPath, request);
        // 8、返回最佳的匹配方法
        return bestMatch.handlerMethod;
    }
    else {
        // 9、如果所有的 mappings 都没有任何一个能匹配上,返回 null
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

2、直接匹配,比如浏览器输入 http://localhost:8080/user/1/games/dota ,它会寻找有没有 @RequestMapping(“/user/1/games/dota”,…) 这个内容的注解
8、通过 /user/1/games/dota 寻找到最佳的匹配方法如下
在这里插入图片描述
代码块六、getHandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    // 1、判断当前 handler 是否是 HandlerExecutionChain 类型,如果不是则新建一个 HandlerExecutionChain
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
    // 2、获取请求路径
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
     
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        // 3、如果处理器拦截器是已经映射过的拦截器
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            // 4、处理器执行链添加拦截器
            chain.addInterceptor(interceptor);
        }
    }
    // 5、返回处理器执行链
    return chain;
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
getHandler是一个方法,用于获取目标处理器的执行。它接受一个HttpServletRequest对象作为参数,并返回一个HandlerExecutionChain对象,该对象包含了要调用的Controller方法以及要执行的拦截器链。在DispatcherServlet的doDispatch方法中,会调用getHandler方法,通过遍历已经准备好的HandlerMapping列表,找到适配当前请求的HandlerMapping,并调用其getHandler方法来获取HandlerExecutionChain对象。如果找到了匹配的HandlerExecutionChain对象,则返回该对象;否则返回null。 在默认的情况下,有三个默认适配器(HttpRequestHandlerAdapter、SimplerControllerHandlerAdapter和RequestMappingHandlerAdapter),这些适配器负责将处理器(handler)适配成HandlerAdapter对象,以便在请求执行过程中使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [getHandler()、getHandlerAdapter()细节](https://blog.csdn.net/weixin_44134725/article/details/112450091)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [spring源码:getHandler和getHandlerAdapter](https://blog.csdn.net/qq_40813329/article/details/119548211)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值