【原創】005 | 搭上SpringBoot請求處理源碼分析專車

前言

若是這是你第二次看到師長,說明你在覬覦個人美色!java

點贊+關注再看,養成習慣mysql

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

專車介紹

該趟專車是開往Spring Boot請求處理源碼分析專車,主要用來分析Spring Boot是如何將咱們的請求路由到指定的控制器方法以及調用執行。程序員

專車問題

  • 爲何咱們在控制器中添加一個方法,使用@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請求,接下里咱們會結合示例進行源碼分析web

專車分析

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

請求初始化

請求流程

一次完成的請求流程就是請求--->處理--->響應,業務邏輯處理最終交由咱們建立的Servlet來進行處理。之前在使用Spring MVC框架的時候,咱們都會在web.xml中配置一個DispathcherServlet。接下來就讓咱們來看看DispathcherServlet的類圖
redis

從如上圖能夠清晰的看到DispatcherServlet的繼承關係。其中一個名爲HttpServlet的類,若是寫過Servlet的應該都比較的熟悉,以往基於Servlet開發,都會建立一個Servlet實現類,繼承HttpServlet並重寫service方法,最後在web.xml中配置咱們咱們建立的Servlet實現類,這樣咱們就能夠使用建立的Servlet實現類來處理咱們的web請求了。sql

HttpServlet初始化

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

初始化方法:HttpServletBean#initmysql優化

@Override
public final void init() throws ServletException {
    // ...省略部分代碼
    
    // Let subclasses do whatever initialization they like.
    // 暴露出去一個方法,可讓子類初始化一些本身想要初始化的內容
    initServletBean();
}

建立WebApplicationContext:FrameworkServlet#initServletBean

@Override
protected final void initServletBean() throws ServletException {
    // ...省略部分代碼
    try {
        // 初始化WebApplicationContext對象
        this.webApplicationContext = initWebApplicationContext();
        // 空實現
        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實現: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實現的分析,咱們能夠得出,全部的初始化操做就是從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的聲明

建立RequestMappingHandlerMapping

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

能夠看到除了建立RequestMappingHandlerMapping對象,其它的都是設置屬性信息,接下來重點分析建立對象部分的代碼

WebMvcConfigurationSupport#createRequestMappingHandlerMapping

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

能夠建立RequestMappingHandlerMapping對象的代碼很簡單,就是調用了無參數構造進行初始化。可是經過查看RequestMappingHandlerMapping的繼承關係,咱們能夠看到該類實現了InitializingBean接口,這也就告訴咱們當看到很簡單的代碼的時候,咱們就要看看類的繼承關係,來看看是否使用其餘形式進行邏輯實現。

既然實現了InitializingBean接口,那就看看建立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());
    // 調用父類的初始化方法
    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 {
        // 根據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) {
    // 根據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類就有list、get、add、update四個方法,遍歷這四個方法,分別建立對應的RequestMappingInfo對象
                // 根據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);
        });
    }
}

根據method獲取RequestMappingInfo對象:RequestMappingHandlerMapping#getMappingForMethod

@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // 根據method對象建立RequestMappingInfo對象
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        // 若是當前方法所在的類也含有@RequestMapping對象,那麼也建立一個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) {
    // 根據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類就有list、get、add、update四個方法,遍歷這四個方法,分別建立對應的RequestMappingInfo對象
                // 根據method獲取RequestMappingInfo對象
                return getMappingForMethod(method, userType);
            }
        });
        if (logger.isTraceEnabled()) {
            logger.trace(formatMappings(userType, methods));
        }
        // 遍歷處理方法
        methods.forEach((method, mapping) -> {
            // 獲取能夠執行的method對象
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            // 註冊處理方法
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

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

public void register(T mapping, Object handler, Method method) {
    // 加寫鎖,加鎖是由於咱們能夠在代碼中手動註冊處理方法,爲了防止併發問題,此處須要加鎖處理
    this.readWriteLock.writeLock().lock();
    try {
        // 建立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();
    }
}

全部方法遍歷完成後的結果以下:

到此RequestMappingHandlerMapping對象建立初始化就結束了

RequestMappingHandlerMapping對象建立總結

  • 調用afterPropertiesSet初始化方法
  • 獲取全部的bean名稱
  • 遍歷全部的bean名稱,若是bean名稱不是以」scopedTarget.「開頭就繼續處理
  • 根據bean名稱獲取bean類型,獲取對應的類型上是否含有@Controller註解或@RequestMapping註解,若是有就繼續處理
  • 獲取當前類中全部的方法,遍歷全部的方法
  • 根據Method對象生成RequestMappingInfo對象,若是類上也頗有@RequestMapping註解,那麼也生成RequestMappingInfo對象,將這兩個RequestMappingInfo對象進行合併
  • 遍歷Method、RequestMappingInfo對應的map集合並註冊到對應的mappingLookup、urlLookup、registry集合中

建立RequestMappingHandlerAdapter

建立RequestMappingHandlerAdapter:WebMvcAutoConfiguration.EnableWebMvcConfiguration#requestMappingHandlerAdapter

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

調用父類建立RequestMappingHandlerAdapter:WebMvcConfigurationSupport#requestMappingHandlerAdapter

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

請求處理

請求處理流程

  • 遍歷全部的HandlerMapping對象,找到匹配當前請求對應的HandlerMethod
  • 將HandlerMethod包裝成HandlerExecutionChain對象
  • 根據HandlerMethod找到HandlerAdapter
  • HandlerAdapter執行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) {
            // 根據HandlerMapping獲取HandlerExecutionChain對象,此處的HandlerMapping就是上面分析過的RequestMappingHandlerMapping對象
            HandlerExecutionChain handler = mapping.getHandler(request);
            // 若是獲取到HandlerExecutionChain對象,那麼直接將HandlerExecutionChain對象返回
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

根據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,而後建立HandlerMethod對象
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        // 釋放鎖
        this.mappingRegistry.releaseReadLock();
    }
}

尋找HandlerMethod對象:AbstractHandlerMethodMapping#lookupHandlerMethod

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

@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、請求參數等
        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舉例,調用AbstractHandlerMethodAdapter#supports

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

從如上分析能夠得出的結論就是最終返回的HandlerAdapter爲RequestMappingHandlerAdapter

HandlerAdapter執行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...
        // 調用HandlerMethod方法
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }
    // ...省略部分代碼
    return mav;
}

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

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

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

調用方法並處理返回值:ServletInvocableHandlerMethod#invokeAndHandle

public void invokeAndHandle(ServletWebRequest webRequest,
                            ModelAndViewContainer mavContainer,
                            Object... providedArgs) throws Exception {
    // 執行請求,獲取返回值
    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);
    }
}

執行請求:InvocableHandlerMethod#invokeForRequest

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

目標方法調用:InvocableHandlerMethod#doInvoke

@Nullable
protected Object doInvoke(Object... args) throws Exception {
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        // 經過反射執行目標方法
        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.
            // 一、獲取handler
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // Determine handler adapter for the current request.
            // 二、獲取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;
                }
            }
            
            // 執行攔截器的前置方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

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

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

            applyDefaultViewName(processedRequest, mv);
            // 執行攔截器的處理方法
            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) {
        // 執行攔截器的後置方法,經常使用語釋放資源
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        // 執行攔截器的後置方法,經常使用語釋放資源
        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執行HandlerMethod

專車回顧

  • 爲何咱們在控制器中添加一個方法,使用@RequestMapping註解標註,指定一個路徑,就能夠用來處理一個web請求?由於在初始化過程當中,會將請求路徑和處理方法進行綁定,咱們在請求ulr的時候,匹配到咱們對應的處理方法,而後調用處理方法,就能夠執行這次的ewb請求了。
  • 若是多個方法的請求路徑一致,Spring Boot是如何處理的?若是多個方法的請求路徑一致,會拿請求方法、請求參數、請求header等,最終會匹配出最符合的一個處理方法,若是匹配出多個結果,就會報錯。

專車遺漏問題

  • SpringBoot如何處理請求參數
  • SpringBoot如何處理返回結果
  • SpringBoot攔截器如何工做

專車擴展

若是是基於微服務開發,那麼該如何定義咱們的服務?

定義微服務接口:

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

定義接口實現:

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

本專車系列文章

【原創】001 | 搭上SpringBoot自動注入源碼分析專車

【原創】002 | 搭上SpringBoot事務源碼分析專車

【原創】003 | 搭上基於SpringBoot事務思想實戰專車

【原創】004 | 搭上SpringBoot事務詭異事件分析專車

最後

師長,【java進階架構師】號主,短短一年在各大平臺斬獲15W+程序員關注,專一分享Java進階、架構技術、高併發、微服務、BAT面試、redis專題、JVM調優、Springboot源碼、mysql優化等20大進階架構專題。

轉載說明:請務必註明來源(本文首發於公衆號:【java進階架構師】)

相關文章
相關標籤/搜索