【原创】005 | 搭上SpringBoot请求处理源码分析专车

前言

如果这是你第二次看到师长,说明你在觊觎我的美色!

点赞+关注再看,养成习惯

没别的意思,就是需要你的窥屏^_^

专车介绍

该趟专车是开往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的类图

从如上图可以清晰的看到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();
    }
}

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

到此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.
            // 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事务诡异事件分析专车

最后

师长,【java进阶架构师】号主,短短一年在各大平台斩获15W+程序员关注,专注分享Java进阶、架构技术、高并发、微服务、BAT面试、redis专题、JVM调优、Springboot源码、mysql优化等20大进阶架构专题。

转载说明:请务必注明来源(本文首发于公众号:【java进阶架构师】)

原文地址:https://www.cnblogs.com/shizhang/p/12058991.html

时间: 2024-10-08 07:38:04

【原创】005 | 搭上SpringBoot请求处理源码分析专车的相关文章

Android 上千实例源码分析以及开源分析

Android 上千实例源码分析以及开源分析(百度云分享) 要下载的直接翻到最后吧,项目实例有点多. 首先 介绍几本书籍(下载包中)吧. 01_Android系统概述 02_Android系统的开发综述 03_Android的Linux内核与驱动程序 04_Android的底层库和程序 05_Android的JAVA虚拟机和JAVA环境 06_Android的GUI系统 07_Android的Audio系统 08_Android的Video 输入输出系统 09_Android的多媒体系统 10_

Hadoop之HDFS原理及文件上传下载源码分析(下)

上篇Hadoop之HDFS原理及文件上传下载源码分析(上)楼主主要介绍了hdfs原理及FileSystem的初始化源码解析, Client如何与NameNode建立RPC通信.本篇将继续介绍hdfs文件上传.下载源解析. 文件上传 先上文件上传的方法调用过程时序图: 其主要执行过程: FileSystem初始化,Client拿到NameNodeRpcServer代理对象,建立与NameNode的RPC通信(楼主上篇已经介绍过了) 调用FileSystem的create()方法,由于实现类为Dis

原创001 | 搭上SpringBoot自动注入源码分析专车

前言 如果这是你第二次看到师长的文章,说明你在觊觎我的美色!O(∩_∩)O哈哈~ 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 本系列为SpringBoot深度源码专车系列,第一篇发车! 专车介绍 该趟专车是开往Spring Boot自动注入原理源码分析的专车 专车问题 Spring Boot何时注入@Autowired标注的属性? 如果注入类型的Bean存在多个Spring Boot是如何处理的? 专车示例 定义接口 public interface PersonService

Hadoop之HDFS原理及文件上传下载源码分析(上)

HDFS原理 首先说明下,hadoop的各种搭建方式不再介绍,相信各位玩hadoop的同学随便都能搭出来. 楼主的环境: 操作系统:Ubuntu 15.10 hadoop版本:2.7.3 HA:否(随便搭了个伪分布式) 文件上传 下图描述了Client向HDFS上传一个200M大小的日志文件的大致过程: 首先,Client发起文件上传请求,即通过RPC与NameNode建立通讯. NameNode与各DataNode使用心跳机制来获取DataNode信息.NameNode收到Client请求后,

Openstack liberty Glance上传镜像源码分析

该文同时发布在[ceph中国社区],署名为Thomas,另外截图不是很清晰,有需要的读者,可以留言索要,谢谢! 在Openstack中创建云主机,首先得有镜像,而Glance模块提供镜像服务功能,包括:镜像的发现.检索及存储等,主要包括:glance-api和glance-registery两个服务,分别负责镜像的存储和元数据管理.下面基于源码,分析下镜像的上传过程. 上传镜像 先通过glance CLI上传镜像,来直观的了解下镜像上传的过程: # glance --debug image-cr

Struts2请求处理流程及源码分析

1.1 Struts2请求处理 1. 一个请求在Struts2框架中的处理步骤: a) 客户端初始化一个指向Servlet容器的请求: b) 根据Web.xml配置,请求首先经过ActionContextCleanUp过滤器,其为可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助(SiteMesh Plugin),主要清理当前线程的ActionContext和Dispatcher: c) 请求经过插件过滤器,如:SiteMesh.etc等过滤器: d) 请求经过核心过滤器Filte

AngularJS 源码分析1

AngularJS简介 angularjs 是google出品的一款MVVM前端框架,包含一个精简的类jquery库,创新的开发了以指令的方式来组件化前端开发,可以去它的官网看看,请戳这里 再贴上一个本文源码分析对应的angularjs源码合并版本1.2.4,精简版的,除掉了所有的注释, 请戳这里 从启动开始说起 定位到4939行,这里是angularjs开始执行初始化的地方,见代码 ? 1 2 3 bindJQuery(), publishExternalAPI(angular), jqLit

Openstack liberty 创建实例快照源码分析1

Openstack liberty中也支持对云主机执行快照,快照是备份系统中一种常用的数据保护技术,在生产系统故障后,能通过快照将系统快速恢复到快照时间点:那Openstack中的云主机快照是否也支持这种故障恢复呢?请看下文: Openstack支持对处于运行或者停止状态的云主机执行快照,另外Openstack既可以从镜像启动云主机,也可以从启动磁盘启动云主机,根据条件组合,可以执行下面4中快照: 镜像启动云主机的离线快照 镜像启动云主机的在线快照 磁盘启动云主机的离线快照 磁盘启动云主机的在线

Appium Server源码分析之作为Bootstrap客户端

Appium Server拥有两个主要的功能: 它是个http服务器,它专门接收从客户端通过基于http的REST协议发送过来的命令 他是bootstrap客户端:它接收到客户端的命令后,需要想办法把这些命令发送给目标安卓机器的bootstrap来驱动uiatuomator来做事情 通过上一篇文章<Appium Server 源码分析之启动运行Express http服务器>我们分析了Appium Server是如何作为一个http服务器进行工作的.那么今天我们就要分析第二点,Appium S