溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

【原創(chuàng)】005 | 搭上SpringBoot請求處理源碼分析專車

發(fā)布時間:2020-07-11 13:54:19 來源:網(wǎng)絡 閱讀:275 作者:師長學不動了 欄目:編程語言

前言

如果這是你第二次看到師長,說明你在覬覦我的美色!

點贊+關注再看,養(yǎng)成習慣

沒別的意思,就是需要你的窺屏^_^

專車介紹

該趟專車是開往Spring Boot請求處理源碼分析專車,主要用來分析Spring Boot是如何將我們的請求路由到指定的控制器方法以及調(diào)用執(zhí)行。

專車問題

  • 為什么我們在控制器中添加一個方法,使用@RequestMapping注解標注,指定一個路徑,就可以用來處理一個web請求?
  • 如果多個方法的請求路徑一致,Spring Boot是如何處理的?

專車示例

@RestController
@RequestMapping("/persons")
public class PersonController {

    private static List<Person> personList = new ArrayList<>();

    static {
        personList.add(new Person(10001, "test1"));
        personList.add(new Person(10002, "test2"));
        personList.add(new Person(10003, "test3"));
        personList.add(new Person(10004, "test4"));
        personList.add(new Person(10005, "test5"));
    }

    @GetMapping("/")
    public List<Person> list() {
        return personList;
    }

    @GetMapping("/{id}")
    public Person get(@PathVariable("id") Integer id) {
        Person defaultPerson = new Person(88888, "default");
        return personList.stream().filter(person -> Objects.equals(person.getId(), id)).findFirst().orElse(defaultPerson);
    }

    @PostMapping("/")
    public void add(@RequestBody Person person) {
        personList.add(person);
    }

    @PutMapping("/")
    public void update(@RequestBody Person person) {
        personList.removeIf(p -> Objects.equals(p.getId(), person.getId()));
        personList.add(person);
    }
}

示例代碼提供了GET、POST、PUT請求,接下里我們會結合示例進行源碼分析

專車分析

此次分析主要從2個大的方面進行分析:請求初始化、請求處理

請求初始化

請求流程

一次完成的請求流程就是請求--->處理--->響應,業(yè)務邏輯處理最終交由我們創(chuàng)建的Servlet來進行處理。以前在使用Spring MVC框架的時候,我們都會在web.xml中配置一個DispathcherServlet。接下來就讓我們來看看DispathcherServlet的類圖
【原創(chuàng)】005 | 搭上SpringBoot請求處理源碼分析專車

從如上圖可以清晰的看到DispatcherServlet的繼承關系。其中一個名為HttpServlet的類,如果寫過Servlet的應該都比較的熟悉,以往基于Servlet開發(fā),都會創(chuàng)建一個Servlet實現(xiàn)類,繼承HttpServlet并重寫service方法,最后在web.xml中配置我們我們創(chuàng)建的Servlet實現(xiàn)類,這樣我們就可以使用創(chuàng)建的Servlet實現(xiàn)類來處理我們的web請求了。

HttpServlet初始化

在我們第一次請求的時候會進行Servlet的初始化,主要用來初始化資源。HttpServlet的init方法由父類GenericServlet聲明,由子類HttpServletBean實現(xiàn)。

初始化方法:HttpServletBean#init

@Override
public final void init() throws ServletException {
    // ...省略部分代碼

    // Let subclasses do whatever initialization they like.
    // 暴露出去一個方法,可以讓子類初始化一些自己想要初始化的內(nèi)容
    initServletBean();
}

創(chuàng)建WebApplicationContext:FrameworkServlet#initServletBean

@Override
protected final void initServletBean() throws ServletException {
    // ...省略部分代碼
    try {
        // 初始化WebApplicationContext對象
        this.webApplicationContext = initWebApplicationContext();
        // 空實現(xiàn)
        initFrameworkServlet();
    }
    // ...省略部分代碼
}

初始化WebApplicationContext對象:FrameworkServlet#initWebApplicationContext

protected WebApplicationContext initWebApplicationContext() {
    // 獲取WebApplicationContext對象
    WebApplicationContext rootContext =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    // ... 省略部分代碼
    if (!this.refreshEventReceived) {
        // Either the context is not a ConfigurableApplicationContext with refresh
        // support or the context injected at construction time had already been
        // refreshed -> trigger initial onRefresh manually here.
        synchronized (this.onRefreshMonitor) {
            // 刷新資源
            onRefresh(wac);
        }
    }

    if (this.publishContext) {
        // Publish the context as a servlet context attribute.
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }

    return wac;
}

刷新資源:DispatcherServlet#onRefresh

@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

初始化策略:DispatcherServlet#initStrategies

protected void initStrategies(ApplicationContext context) {
    // 初始化多文件解析器
    initMultipartResolver(context);
    // 初始化本地化解析器
    initLocaleResolver(context);
    // 初始化主題解析器
    initThemeResolver(context);
    // 初始化HandlerMapping
    initHandlerMappings(context);
    // 初始化HandlerAdapter
    initHandlerAdapters(context);
    // 初始化異常解析器
    initHandlerExceptionResolvers(context);
    // 初始化請求到視圖名稱翻譯器
    initRequestToViewNameTranslator(context);
    // 初始化視圖解析器
    initViewResolvers(context);
    initFlashMapManager(context);
}

來看一下初始化HandlerMapping實現(xiàn):DispatcherServlet#initHandlerMappings

private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;

    if (this.detectAllHandlerMappings) {
        // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
        // 從IOC容器中獲取類型為HandlerMapping的bean
        // 對應的bean有RequestMappingHandlerMapping、SimpleUrlHandlerMapping、WelcomePageHandlerMapping
        Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // We keep HandlerMappings in sorted order.
            // 對HandlerMapping進行排序
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
}

通過對初始化HandlerMapping實現(xiàn)的分析,我們可以得出,所有的初始化操作就是從IOC容器中獲取相應類型的Bean,然后進行屬性賦值。

既然能從IOC容器中獲取到HandlerMapping bean,那么一定存在定義bean 的地方。打開WebMvcAutoConfiguration類,可以看到如下代碼

/**
 * Configuration equivalent to {@code @EnableWebMvc}.
 * 此配置等同于使用@EnableWebMvc注解
 */
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {

    private final WebMvcProperties mvcProperties;

    private final ListableBeanFactory beanFactory;

    private final WebMvcRegistrations mvcRegistrations;

    public EnableWebMvcConfiguration(
        ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
        ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider,
        ListableBeanFactory beanFactory) {
        this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
        this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
        this.beanFactory = beanFactory;
    }

    // 聲明RequestMappingHandlerAdapter bean
    @Bean
    @Override
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
        RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
        adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
                                                || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
        return adapter;
    }

    // 聲明RequestMappingHandlerMapping bean
    @Bean
    @Primary
    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        // Must be @Primary for MvcUriComponentsBuilder to work
        return super.requestMappingHandlerMapping();
    }
}

在如上代碼中可以看到HandlerAdapter和HandlerMapping bean的聲明

創(chuàng)建RequestMappingHandlerMapping
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
    // 創(chuàng)建RequestMappingHandlerMapping對象
    RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
    // 設置屬性
    mapping.setOrder(0);
    // 設置攔截器
    mapping.setInterceptors(getInterceptors());
    mapping.setContentNegotiationManager(mvcContentNegotiationManager());
    mapping.setCorsConfigurations(getCorsConfigurations());
    // ...省略部分代碼
    return mapping;
}

可以看到除了創(chuàng)建RequestMappingHandlerMapping對象,其它的都是設置屬性信息,接下來重點分析創(chuàng)建對象部分的代碼

WebMvcConfigurationSupport#createRequestMappingHandlerMapping

protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
    return new RequestMappingHandlerMapping();
}

可以創(chuàng)建RequestMappingHandlerMapping對象的代碼很簡單,就是調(diào)用了無參數(shù)構造進行初始化。但是通過查看RequestMappingHandlerMapping的繼承關系,我們可以看到該類實現(xiàn)了InitializingBean接口,這也就告訴我們當看到很簡單的代碼的時候,我們就要看看類的繼承關系,來看看是否使用其他形式進行邏輯實現(xiàn)。

既然實現(xiàn)了InitializingBean接口,那就看看創(chuàng)建bean后的初始化方法afterPropertiesSet

@Override
public void afterPropertiesSet() {
    this.config = new RequestMappingInfo.BuilderConfiguration();
    this.config.setUrlPathHelper(getUrlPathHelper());
    this.config.setPathMatcher(getPathMatcher());
    this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
    this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
    this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
    this.config.setContentNegotiationManager(getContentNegotiationManager());
    // 調(diào)用父類的初始化方法
    super.afterPropertiesSet();
}
@Override
**public** **void** **afterPropertiesSet**() {
    // 初始化處理方法
    initHandlerMethods();
}

初始化處理方法:AbstractHandlerMethodMapping#initHandlerMethods

protected void initHandlerMethods() {
    // 獲取并遍歷候選bean名稱,候選bean就是從IOC容器中獲取類型為Object的bean名稱,也就是所有的Bean名稱
    for (String beanName : getCandidateBeanNames()) {
        // 如果bean的名稱不以“scopedTarget.”開頭,才進行處理
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            // 處理候選bean名稱
            processCandidateBean(beanName);
        }
    }
    handlerMethodsInitialized(getHandlerMethods());
}

處理候選bean名稱:AbstractHandlerMethodMapping#processCandidateBean

protected void processCandidateBean(String beanName) {
    Class<?> beanType = null;
    try {
        // 根據(jù)bean的名稱獲取對應bean的類型
        beanType = obtainApplicationContext().getType(beanName);
    }
    catch (Throwable ex) {
        // An unresolvable bean type, probably from a lazy bean - let's ignore it.
        if (logger.isTraceEnabled()) {
            logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
        }
    }
    // 如果bean的類型不為空并且對應類上含有@Controller注解或者@RequestMapping注解
    if (beanType != null && isHandler(beanType)) {
        // 推斷處理方法
        detectHandlerMethods(beanName);
    }
}

推斷處理方法:AbstractHandlerMethodMapping#detectHandlerMethods

protected void detectHandlerMethods(Object handler) {
    // 根據(jù)bean名稱獲取類型
    Class<?> handlerType = (handler instanceof String ?
                            obtainApplicationContext().getType((String) handler) : handler.getClass());

    if (handlerType != null) {
        Class<?> userType = ClassUtils.getUserClass(handlerType);
        // 獲取處理方法
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                                                                       (MethodIntrospector.MetadataLookup<T>) method -> {
            try {
                // selectMethods方法獲取當前類中所有的方法,針對PersonController類就有l(wèi)ist、get、add、update四個方法,遍歷這四個方法,分別創(chuàng)建對應的RequestMappingInfo對象
                // 根據(jù)method獲取RequestMappingInfo對象
                return getMappingForMethod(method, userType);
            }
        });
        if (logger.isTraceEnabled()) {
            logger.trace(formatMappings(userType, methods));
        }
        methods.forEach((method, mapping) -> {
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

根據(jù)method獲取RequestMappingInfo對象:RequestMappingHandlerMapping#getMappingForMethod

@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // 根據(jù)method對象創(chuàng)建RequestMappingInfo對象
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        // 如果當前方法所在的類也含有@RequestMapping對象,那么也創(chuàng)建一個RequestMappingInfo對象
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        if (typeInfo != null) {
            // 將兩個RequestMappingInfo對象進行合并,比如我們PersonController上指定@RequestMapping("/persons"),針對list方法,list方法上指定@RequestMapping("/"),那么合并后的映射路徑就是/persons/
            info = typeInfo.combine(info);
        }
        String prefix = getPathPrefix(handlerType);
        if (prefix != null) {
            info = RequestMappingInfo.paths(prefix).build().combine(info);
        }
    }
    // 返回RequestMappingInfo對象
    return info;
}

回到推斷處理方法中:AbstractHandlerMethodMapping#detectHandlerMethods

protected void detectHandlerMethods(Object handler) {
    // 根據(jù)bean名稱獲取類型
    Class<?> handlerType = (handler instanceof String ?
                            obtainApplicationContext().getType((String) handler) : handler.getClass());

    if (handlerType != null) {
        Class<?> userType = ClassUtils.getUserClass(handlerType);
        // 獲取處理方法,每個方法都有對應的RequestMappingInfo對象
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                                                                       (MethodIntrospector.MetadataLookup<T>) method -> {
            try {
                // selectMethods方法中當前類中所有的方法,針對PersonController類就有l(wèi)ist、get、add、update四個方法,遍歷這四個方法,分別創(chuàng)建對應的RequestMappingInfo對象
                // 根據(jù)method獲取RequestMappingInfo對象
                return getMappingForMethod(method, userType);
            }
        });
        if (logger.isTraceEnabled()) {
            logger.trace(formatMappings(userType, methods));
        }
        // 遍歷處理方法
        methods.forEach((method, mapping) -> {
            // 獲取可以執(zhí)行的method對象
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            // 注冊處理方法
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

注冊處理方法:AbstractHandlerMethodMapping.MappingRegistry#register

public void register(T mapping, Object handler, Method method) {
    // 加寫鎖,加鎖是因為我們可以在代碼中手動注冊處理方法,為了防止并發(fā)問題,此處需要加鎖處理
    this.readWriteLock.writeLock().lock();
    try {
        // 創(chuàng)建HandlerMethod對象
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        assertUniqueMethodMapping(handlerMethod, mapping);
        // 將RequestMappingInfo對象和HandlerMethod對象添加到map集合中
        this.mappingLookup.put(mapping, handlerMethod);

        List<String> directUrls = getDirectUrls(mapping);
        for (String url : directUrls) {
            // 將url和RequestMappingInfo對象添加到map集合中
            this.urlLookup.add(url, mapping);
        }

        String name = null;
        if (getNamingStrategy() != null) {
            name = getNamingStrategy().getName(handlerMethod, mapping);
            addMappingName(name, handlerMethod);
        }

        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            this.corsLookup.put(handlerMethod, corsConfig);
        }
        // 將RequestMappingInfo和MappingRegistration對象添加到map集合中
        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }
    finally {
        // 釋放鎖
        this.readWriteLock.writeLock().unlock();
    }
}

所有方法遍歷完成后的結果如下:
【原創(chuàng)】005 | 搭上SpringBoot請求處理源碼分析專車

到此RequestMappingHandlerMapping對象創(chuàng)建初始化就結束了

RequestMappingHandlerMapping對象創(chuàng)建總結
  • 調(diào)用afterPropertiesSet初始化方法
  • 獲取所有的bean名稱
  • 遍歷所有的bean名稱,如果bean名稱不是以”scopedTarget.“開頭就繼續(xù)處理
  • 根據(jù)bean名稱獲取bean類型,獲取對應的類型上是否含有@Controller注解或@RequestMapping注解,如果有就繼續(xù)處理
  • 獲取當前類中所有的方法,遍歷所有的方法
  • 根據(jù)Method對象生成RequestMappingInfo對象,如果類上也很有@RequestMapping注解,那么也生成RequestMappingInfo對象,將這兩個RequestMappingInfo對象進行合并
  • 遍歷Method、RequestMappingInfo對應的map集合并注冊到對應的mappingLookup、urlLookup、registry集合中
創(chuàng)建RequestMappingHandlerAdapter

創(chuàng)建RequestMappingHandlerAdapter:WebMvcAutoConfiguration.EnableWebMvcConfiguration#requestMappingHandlerAdapter

@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
    // 調(diào)用父類創(chuàng)建RequestMappingHandlerAdapter對象
    RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
    // ...省略部分代碼
    return adapter;
}

調(diào)用父類創(chuàng)建RequestMappingHandlerAdapter:WebMvcConfigurationSupport#requestMappingHandlerAdapter

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
    // 創(chuàng)建RequestMappingHandlerAdapter對象
    RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
    // 省略部分代碼
    return adapter;
}

請求處理

請求處理流程
  • 遍歷所有的HandlerMapping對象,找到匹配當前請求對應的HandlerMethod
  • 將HandlerMethod包裝成HandlerExecutionChain對象
  • 根據(jù)HandlerMethod找到HandlerAdapter
  • HandlerAdapter執(zhí)行HandlerMethod
匹配HandlerMethod并包裝成HandlerExecutionChain對象
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HandlerExecutionChain mappedHandler = null;
    // 匹配HandlerMethod并包裝成HandlerExecutionChain對象
    mappedHandler = getHandler(processedRequest);
}

獲取HandlerExecutionChain對象:DispatcherServlet#getHandler

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        // 遍歷所有的HandlerMapping
        for (HandlerMapping mapping : this.handlerMappings) {
            // 根據(jù)HandlerMapping獲取HandlerExecutionChain對象,此處的HandlerMapping就是上面分析過的RequestMappingHandlerMapping對象
            HandlerExecutionChain handler = mapping.getHandler(request);
            // 如果獲取到HandlerExecutionChain對象,那么直接將HandlerExecutionChain對象返回
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

根據(jù)HandlerMapping獲取HandlerExecutionChain對象:AbstractHandlerMapping#getHandler

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 獲取HandlerMethod對象
    Object handler = getHandlerInternal(request);

    // ...省略部分代碼

    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    // ...省略部分代碼
    return executionChain;
}

獲取HandlerMethod對象

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 獲取請求的路徑,假設此處請求的路徑為/persons/
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    // 加鎖
    this.mappingRegistry.acquireReadLock();
    try {
        // 尋找HandlerMethod對象
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        // 獲取HandlerMethod所在類對應的bean,然后創(chuàng)建HandlerMethod對象
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        // 釋放鎖
        this.mappingRegistry.releaseReadLock();
    }
}

尋找HandlerMethod對象:AbstractHandlerMethodMapping#lookupHandlerMethod

在該方法之前再看一下上文中對RequestMappingHandlerMapping分析的結果

【原創(chuàng)】005 | 搭上SpringBoot請求處理源碼分析專車

@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    // 從urlLookup屬性中找到當前請求路徑對應的RequestMappingInfo信息
    // 假設請求的路徑為/persons/,那么此處得到的結果有3個
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        // 尋找最匹配的RequestMappingInfo
        // 匹配的方式包括:請求方法、請求header、請求參數(shù)等
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        // No choice but to go through all mappings...
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    if (!matches.isEmpty()) {
        Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
        matches.sort(comparator);
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            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 + "}");
            }
        }
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
        handleMatch(bestMatch.mapping, lookupPath, request);
        // 返回匹配的HandlerMethod
        return bestMatch.handlerMethod;
    }
    else {
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}
獲取HandlerAdapter
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // Determine handler adapter for the current request.
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
}

獲取HandlerAdapter:DispatcherServlet#getHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            // 如果當前HandlerAdapter支持當前要處理的HnadlerMethod,那么就返回此HandlerAdapter
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
                               "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

匹配方法:此處拿RequestMappingHandlerAdapter舉例,調(diào)用AbstractHandlerMethodAdapter#supports

public final boolean supports(Object handler) {
   // 如果當前的hander是HandlerMethod,則返回true;后一個表達式直接返回的就是true
   return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

從如上分析可以得出的結論就是最終返回的HandlerAdapter為RequestMappingHandlerAdapter

HandlerAdapter執(zhí)行HandlerMethod
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}

處理目標方法:RequestMappingHandlerAdapter#handleInternal

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
                                      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ModelAndView mav;
    checkRequest(request);

    // Execute invokeHandlerMethod in synchronized block if required.
    if (this.synchronizeOnSession) {
        // ...省略部分代碼
    }
    else {
        // No synchronization on session demanded at all...
        // 調(diào)用HandlerMethod方法
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }
    // ...省略部分代碼
    return mav;
}

調(diào)用HandlerMethod方法:RequestMappingHandlerAdapter#invokeHandlerMethod

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                           HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

        // 創(chuàng)建ServletInvocableHandlerMethod對象,就是把handlerMethod對象的屬性賦值給ServletInvocableHandlerMethod對象的屬性
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        // ...省略部分代碼
        // 調(diào)用方法并處理返回值
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }

        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}

調(diào)用方法并處理返回值:ServletInvocableHandlerMethod#invokeAndHandle

public void invokeAndHandle(ServletWebRequest webRequest,
                            ModelAndViewContainer mavContainer,
                            Object... providedArgs) throws Exception {
    // 執(zhí)行請求,獲取返回值
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    setResponseStatus(webRequest);

    // ...省略部分代碼

    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        // 處理返回值
        this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
}

執(zhí)行請求:InvocableHandlerMethod#invokeForRequest

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                               Object... providedArgs) throws Exception {
    // 獲取方法參數(shù)
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }
    // 目標方法調(diào)用
    return doInvoke(args);
}

目標方法調(diào)用:InvocableHandlerMethod#doInvoke

@Nullable
protected Object doInvoke(Object... args) throws Exception {
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        // 通過反射執(zhí)行目標方法
        return getBridgedMethod().invoke(getBean(), args);
    }
    // ...省略部分代碼
}

到此請求處理的源碼分析就結束了,最終再來看看doDispatch完整的方法:DispatcherServlet#doDispatch

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.
            // 1、獲取handler
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // Determine handler adapter for the current request.
            // 2、獲取HandlerAdapter
            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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            // 執(zhí)行攔截器的前置方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // Actually invoke the handler.
            // 調(diào)用目標方法
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);
            // 執(zhí)行攔截器的處理方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        // 處理結果
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        // 執(zhí)行攔截器的后置方法,常用語釋放資源
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        // 執(zhí)行攔截器的后置方法,常用語釋放資源
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                               new NestedServletException("Handler processing failed", 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);
            }
        }
    }
}

專車總結

一次請求原理如下:

  • 請求初始化
  • 請求處理

請求初始化

  • 初始化RequestMappingHandlerMapping
  • 初始化RequestMappingHandlerAdapter

請求處理

  • 獲取HandlerMethod,組裝HandlerExecutionChain對象
  • 獲取HandlerAdapter
  • 使用HandlerAdapter執(zhí)行HandlerMethod

專車回顧

  • 為什么我們在控制器中添加一個方法,使用@RequestMapping注解標注,指定一個路徑,就可以用來處理一個web請求?因為在初始化過程中,會將請求路徑和處理方法進行綁定,我們在請求ulr的時候,匹配到我們對應的處理方法,然后調(diào)用處理方法,就可以執(zhí)行此次的ewb請求了。
  • 如果多個方法的請求路徑一致,Spring Boot是如何處理的?如果多個方法的請求路徑一致,會拿請求方法、請求參數(shù)、請求header等,最終會匹配出最符合的一個處理方法,如果匹配出多個結果,就會報錯。

專車遺漏問題

  • SpringBoot如何處理請求參數(shù)
  • SpringBoot如何處理返回結果
  • SpringBoot攔截器如何工作

專車擴展

如果是基于微服務開發(fā),那么該如何定義我們的服務?

定義微服務接口:

@RequestMapping("/persons")
public interface PersonApi {

    /**
     * list
     *
     * @return
     */
    @GetMapping("/")
    List<Person> list();

    /**
     * get
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    Person get(@PathVariable("id") Integer id);

    /**
     * add
     *
     * @param person
     * @return
     */
    @PostMapping("/")
    void add(@RequestBody Person person);

    /**
     * update
     *
     * @param person
     * @return
     */
    @PutMapping("/")
    void update(@RequestBody Person person);
}

定義接口實現(xiàn):

@RestController
public class PersonController implements PersonApi {

    private static List<Person> personList = new ArrayList<>();

    static {
        personList.add(new Person(10001, "test1"));
        personList.add(new Person(10002, "test2"));
        personList.add(new Person(10003, "test3"));
        personList.add(new Person(10004, "test4"));
        personList.add(new Person(10005, "test5"));
    }

    @Override
    public List<Person> list() {
        return personList;
    }

    @Override
    public Person get(Integer id) {
        Person defaultPerson = new Person(88888, "default");
        return personList.stream().filter(person -> Objects.equals(person.getId(), id)).findFirst().orElse(defaultPerson);
    }

    @Override
    public void add(Person person) {
        personList.add(person);
    }

    @Override
    public void update(Person person) {
        personList.removeIf(p -> Objects.equals(p.getId(), person.getId()));
        personList.add(person);
    }
}

本專車系列文章

【原創(chuàng)】001 | 搭上SpringBoot自動注入源碼分析專車

【原創(chuàng)】002 | 搭上SpringBoot事務源碼分析專車

【原創(chuàng)】003 | 搭上基于SpringBoot事務思想實戰(zhàn)專車

【原創(chuàng)】004 | 搭上SpringBoot事務詭異事件分析專車

最后

師長,專注分享Java進階、架構技術、高并發(fā)、微服務、BAT面試、redis專題、JVM調(diào)優(yōu)、Springboot源碼、mysql優(yōu)化等20大進階架構專題。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI