编程语言
首页 > 编程语言> > SpringMVC 源码解析笔记

SpringMVC 源码解析笔记

作者:互联网

目录

作者笔记仓库https://github.com/seazean/javanotes

欢迎各位关注我的笔记仓库,clone 仓库到本地后使用 Typora 阅读效果更好,因为有目录侧边栏能更好的看出层级。

调度函数

请求进入原生的 HttpServlet 的 doGet() 方法处理,调用子类 FrameworkServlet 的 doGet() 方法,最终调用 DispatcherServlet 的 doService() 方法,为请求设置相关属性后调用 doDispatch(),请求和响应的以参数的形式传入

//request 和 response 为 Java 原生的类
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);

            // 找到当前请求使用哪个 HandlerMapping(Controller的方法)处理,返回执行链
            mappedHandler = getHandler(processedRequest);
            // 没有合适的处理请求的方式 HandlerMapping 直接返回
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            //根据映射器获取当前 handler 处理器适配器,用来处理当前的请求
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            // 获取发出此次请求的方法
            String method = request.getMethod();
            // 判断请求是不是 GET 方法
            boolean isGet = HttpMethod.GET.matches(method);
            if (isGet || HttpMethod.HEAD.matches(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            // 执行处理方法,返回的是 ModelAndView 对象,封装了所有的返回值数据
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
			// 设置视图名字
            applyDefaultViewName(processedRequest, mv);
            // 执行拦截器链中的方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        } catch (Exception ex) {
            dispatchException = ex;
        }
        
        // 处理 程序调用的结果,进行结果派发
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    //....
}

笔记参考视频:https://www.bilibili.com/video/BV19K4y1L7MT


请求映射

映射器

doDispatch() 中调用 getHandler 方法获取所有的映射器

总体流程:

访问 URL:http://localhost:8080/user

@GetMapping("/user")
public String getUser(){
    return "GET";
}

HandlerMapping 处理器映射器,保存了所有 @RequestMappinghandler 的映射规则

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        //遍历所有的 HandlerMapping
        for (HandlerMapping mapping : this.handlerMappings) {
            //尝试去每个 HandlerMapping 中匹配当前请求的处理
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}


适配器

doDispatch() 中 调用 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler())

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        //遍历所有的 HandlerAdapter
        for (HandlerAdapter adapter : this.handlerAdapters) {
            //判断当前适配器是否支持当前 handle
            //return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler))
            //这里返回的是True,
            if (adapter.supports(handler)) {
                //返回的是 RequestMappingHandlerAdapter
                return adapter;
            }
        }
    }
    throw new ServletException();
}

方法执行

执行流程

实例代码:

@GetMapping("/params")
public String param(Map<String, Object> map, Model model, HttpServletRequest request) {
    map.put("k1", "v1");			//都可以向请求域中添加数据
    model.addAttribute("k2", "v2");	//它们两个都在数据封装在 BindingAwareModelMap
    request.setAttribute("m", "HelloWorld");
    return "forward:/success";
}

doDispatch() 中调用 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()) 执行目标方法

AbstractHandlerMethodAdapter#handleRequestMappingHandlerAdapter#handleInternal

protected ModelAndView handleInternal(HttpServletRequest request,
                                      HttpServletResponse response, 
                                      HandlerMethod handlerMethod) throws Exception {
    // 是否是 Session 加锁
    if (this.synchronizeOnSession) {
    } else {
        //使用适配器执行方法
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }
	//是否在响应头中设置了缓存的属性
    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        //是否通过 SessionAttributes 设置了会话属性
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            //使用给定的缓存秒数并生成相应的 HTTP 标头
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            //根据此生成器的设置准备接受的响应,设置缓存的时间
            prepareResponse(response);
        }
    }
    return mav;
}
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                           HttpServletResponse response, 
                                           HandlerMethod handlerMethod) throws Exception {
	//封装成 SpringMVC 的接口,用于通用 Web 请求拦截器,使能够访问通用请求元数据,而不是用于实际处理请求
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        //WebDataBinder 用于从 Web 请求参数到 JavaBean 对象的数据绑定,获取创建该实例的工厂
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        //创建 Model 实例,用于向模型添加属性
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
		//方法执行器
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        
        //参数解析器,有很多
        if (this.argumentResolvers != null) {
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        //返回值处理器,也有很多
        if (this.returnValueHandlers != null) {
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        //设置数据绑定器
        invocableMethod.setDataBinderFactory(binderFactory);
        //设置参数检查器
		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
   
        //新建一个 ModelAndViewContainer 并进行初始化和一些属性的填充
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            
        //设置一些属性
        
        //执行目标方法
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        //异步请求
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
		// 获取 ModelAndView 对象,封装了 ModelAndViewContainer
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}

ServletInvocableHandlerMethod#invokeAndHandle:执行目标方法

RequestMappingHandlerAdapter#getModelAndView:获取 ModelAndView 对象


参数解析

解析自定义的 JavaBean 为例

进入源码:ModelAttributeMethodProcessor#resolveArgument


响应处理

响应数据

以 Person 为例:

@ResponseBody  		//利用返回值处理器里面的消息转换器进行处理
@GetMapping(value = "/person")
public Person getPerson(){
    Person person = new Person();
    person.setAge(28);
    person.setBirth(new Date());
    person.setUserName("zhangsan");
    return person;
}

直接进入方法执行完后的逻辑 ServletInvocableHandlerMethod#invokeAndHandle:

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
                            Object... providedArgs) throws Exception {
	// 执行目标方法,return person 对象
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    // 设置状态码
    setResponseStatus(webRequest);

    // 判断方法是否有返回值
    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            disableContentCachingIfNecessary(webRequest);
            mavContainer.setRequestHandled(true);
            return;
        }
    }	//返回值是字符串
    else if (StringUtils.hasText(getResponseStatusReason())) {
        //设置请求处理完成
        mavContainer.setRequestHandled(true);
        return;
	// 设置请求没有处理完成,还需要进行返回值的逻辑
    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        // 返回值的处理
        this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {}
}

HandlerMethodReturnValueHandlerComposite#selectHandler

RequestResponseBodyMethodProcessor#handleReturnValue:处理返回值


协商策略

开启基于请求参数的内容协商模式:(SpringBoot 方式)

spring.mvc.contentnegotiation:favor-parameter: true  #开启请求参数内容协商模式

发请求: http://localhost:8080/person?format=json,解析 format

策略类为 ParameterContentNegotiationStrategy,运行流程如下:

自定义内容协商策略:

public class WebConfig implements WebMvcConfigurer {
    @Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override	//自定义内容协商策略
            public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
                Map<String, MediaType> mediaTypes = new HashMap<>();
                mediaTypes.put("json", MediaType.APPLICATION_JSON);
                mediaTypes.put("xml",MediaType.APPLICATION_XML);
                mediaTypes.put("person",MediaType.parseMediaType("application/x-person"));
                //指定支持解析哪些参数对应的哪些媒体类型
                ParameterContentNegotiationStrategy parameterStrategy = new ParameterContentNegotiationStrategy(mediaTypes);

                //请求头解析
                HeaderContentNegotiationStrategy headStrategy = new HeaderContentNegotiationStrategy();

                //添加到容器中,即可以解析请求头 又可以解析请求参数
                configurer.strategies(Arrays.asList(parameterStrategy,headStrategy));
            }
            
            @Override 	//自定义消息转换器
            public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
                converters.add(new GuiguMessageConverter());
            }
        }
    }
}

也可以自定义 HttpMessageConverter,实现 HttpMessageConverter 接口重写方法即可


视图解析

返回解析

请求处理:

@GetMapping("/params")
public String param(){
	return "forward:/success";
    //return "redirect:/success";
}

进入执行方法逻辑 ServletInvocableHandlerMethod#invokeAndHandle,进入 this.returnValueHandlers.handleReturnValue

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
                              ModelAndViewContainer mavContainer, NativeWebRequest webRequest)  {
	//获取合适的返回值处理器:调用 if (handler.supportsReturnType(returnType))判断是否支持
    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
    if (handler == null) {
        throw new IllegalArgumentException();
    }
    //使用处理器处理返回值
    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

结果派发

doDispatch()中的 processDispatchResult:处理派发结果

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, 
                                   @Nullable ModelAndView mv,
                                   @Nullable Exception exception) throws Exception {
    boolean errorView = false;
    if (exception != null) {
    }
    // mv 是 ModelAndValue
    if (mv != null && !mv.wasCleared()) {
        // 渲染视图
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {}  
}

DispatcherServlet#render:

标签:return,请求,SpringMVC,request,mavContainer,获取,源码,解析,response
来源: https://www.cnblogs.com/seazean/p/15095819.html