41

搭上 Spring Boot 请求处理源码分析专车

 4 years ago
source link: https://mp.weixin.qq.com/s?__biz=MzAxMjEwMzQ5MA%3D%3D&%3Bmid=2448888575&%3Bidx=2&%3Bsn=da8fe312cbb820da90da7ba32a1b11a0&%3Bchksm=8fb548d2b8c2c1c458416572e5568c502188f3dc09de5b9eee77ce65e2534f82ab4052f6e604&%3Bscene=21
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

发车啦,发车啦,上车要求:

点击左上方的“ java进阶架构师 ”进入页面

选择右上角的“ 星标 公众号 ”上车!

fMjQnuV.jpg!web

专车介绍

该趟专车是开往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请求,接下里我们会结合示例进行源码分析

专车分析

此次分析主要从2个大的方面进行分析:请求初始化、请求处理

请求初始化

请求流程

一次完成的请求流程就是请求--->处理--->响应,业务逻辑处理最终交由我们创建的Servlet来进行处理。以前在使用Spring MVC框架的时候,我们都会在web.xml中配置一个DispathcherServlet。接下来就让我们来看看DispathcherServlet的类图

IbmuAzr.jpg!web

从如上图可以清晰的看到DispatcherServlet的继承关系。其中一个名为HttpServlet的类,如果写过Servlet的应该都比较的熟悉,以往基于Servlet开发,都会创建一个Servlet实现类,继承HttpServlet并重写service方法,最后在web.xml中配置我们我们创建的Servlet实现类,这样我们就可以使用创建的Servlet实现类来处理我们的web请求了。

HttpServlet初始化

在我们第一次请求的时候会进行Servlet的初始化,主要用来初始化资源。HttpServlet的init方法由父类GenericServlet声明,由子类HttpServletBean实现。

初始化方法:HttpServletBean#init

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

所有方法遍历完成后的结果如下:

viU77jm.jpg!web

到此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分析的结果

viU77jm.jpg!web
@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.
            // 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;
                }
            }
			
            // 执行拦截器的前置方法
            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事务诡异事件分析专车

————   e n d  ————

微服务、高并发、JVM调优、面试专栏等 20 大进阶架构师专题请 关注 公众号 Java进阶架构师 后在 菜单栏 查看

RreMve3.gif

看到这里,说明你喜欢本文

你的转发 ,是对我最大的鼓励! 在看 亦是支持


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK