《Spring Boot源码博客》
Spring MVC处理一个REST请求的过程如下
Spring MVC核心流程如下:
一、系统启动阶段初始化请求与Controller方法的映射集合。
二、根据请求查找对应的Controller方法。
三、解析请求参数,通过反射执行Controller方法。
四、处理返回结果。
一、初始化阶段
在初始化阶段需要了解几个Spring MVC组件
1、DispatcherServlet:为客户端的请求提供通用的处理方法,请求分发给各个处理器(Controller方法属于处理器)
2、HandlerMapping:是一个接口,定义请求和处理程序对象之间的映射关系。
2.1、 RequestMappingHandlerMapping:HandlerMapping的实现类,存储请求和Controller方法的映射关系。
2.1.1、RequestMappingInfo 封装了请求信息,HandlerMethod封装了Controller方法。例如:
@RequestMapping("/test2")
public class Test2Controller {
@GetMapping("/path/{userId}")
public Result path(@PathVariable("userId") long userId) {
}
}
对于上面的代码。RequestMappingInfo保存请求类型GET、请求路径/test2/path/{userId}等信息。HandlerMethod保存着Test2Controller#path(Long)方法。
下图是Spring MVC处理请求的部分流程,DispatcherServlet接收请求,并使用RequestMappingHandlerMapping找出请求对应的Contoller方法:
上图左边的大橙色框,this.handlerMappings中的this是指DispatcherServlet,即handlerMappings是DispatcherServlet的属性。this.handlerMappings橙色框里面有个小的橙色框,表示RequestMappingHandlerMapping是this.handlerMappings列表的一个元素。
新建一个Controller,启动Spring MVC项目,探究Spring MVC初始化阶段做了什么。
1、在AbstractHandlerMethodMapping#processCandidateBean()打断点,启动Spring MVC。
/**
* 创建bean时,会调用本方法。
* 若类上有@Controller或者@RequestMapping。执行detectHandlerMethods(beanName)
*/
protected void processCandidateBean(String beanName) {
...仅展示主要代码
// beanType是类Class
// isHandler(beanType),Class上有@Controller或者@RequestMapping返回true
if (beanType != null && isHandler(beanType)) {
// 提取Controller类的url与方法的关系
detectHandlerMethods(beanName);
}
}
1.1、detectHandlerMethods(beanName)解析
/**
* 源码位置 AbstractHandlerMethodMapping#detectHandlerMethods(java.lang.Object)
* 在bean中查找处理程序方法
*/
protected void detectHandlerMethods(Object handler) {
...仅展示主要代码
//寻找方法上有@RequestMapping注解的Method实例。
Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> {
// 返回RequestMappingInfo对象
return getMappingForMethod(method, userType);
});
//将获取到的Method对象注册到HandlerMapping中去
methods.forEach((method, mapping) -> {
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
1.1.1、getMappingForMethod(method, userType)解析
/**
* 使用方法和类上的@RequestMapping创建RequestMappingInfo
*/
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 先使用方法上的@RequestMapping信息创建RequestMappingInfo
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 再使用类上的@RequestMapping信息创建RequestMappingInfo
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
//将两个信息合并
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).build().combine(info);
}
}
return info;
}
1.1.2、registerHandlerMethod(handler, invocableMethod, mapping) 解析。在AbstractHandlerMethodMapping.MappingRegistry#register(java.lang.Object, java.lang.Object, java.lang.reflect.Method)方法中打断点
/**
* 源码地址:AbstractHandlerMethodMapping.MappingRegistry#register(java.lang.Object, java.lang.Object, java.lang.reflect.Method)
* RequestMappingHandlerMapping继承了AbstractHandlerMethodMapping
* register(T mapping, Object handler, Method method)在RequestMappingHandlerMapping创建时执行
*/
public void register(T mapping, Object handler, Method method) {
...仅展示主要代码
/**
* handler是Controller类在IOC中的名字,例如test1Controller
* method是Controller有@RequestMapping标注的方法
* 通过两者封装创建出HandlerMethod对象
*/
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
/**
* 创建及注册 MappingRegistration 信息
* this.registry是RequestMappingHandlerMapping.MappingRegistry#registry,是Map<T, MappingRegistration<T>>类型
*
* mapping是RequestMappingInfo类型,存储请求信息
* MappingRegistration实例包含了Controller方法
* 至此,this.registry便是存储了请求信息和Controller方法的映射关系
*/
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
通过上面的的步骤,RequestMappingHandlerMapping实例便初始化好了。
接下来便是将RequestMappingHandlerMapping实例添加到DispatcherServlet的handlerMappings属性中,在DispatcherServlet#initStrategies()打断点调试。
1、DispatcherServlet#initStrategies()解析
/**
* 源码位置:DispatcherServlet#initStrategies(org.springframework.context.ApplicationContext)
* 初始化DispatcherServlet使用的策略对象
*/
protected void initStrategies(ApplicationContext context) {
//初始化文件上传处理器
initMultipartResolver(context);
//初始化国际化配置
initLocaleResolver(context);
//初始化主题处理器
initThemeResolver(context);
//初始化HandlerMapping
initHandlerMappings(context);
//初始化HandlerAdapter
//HandlerAdapter用来调用具体的方法对用户发来的请求来进行处理
initHandlerAdapters(context);
//初始化异常处理器,
// HandlerExceptionResolver是用来对请求处理过程中产生的异常进行处理
initHandlerExceptionResolvers(context);
//RequestToViewNameTranslator用于在视图路径为空的时候,自动解析请求
//去获取ViewName
initRequestToViewNameTranslator(context);
//初始化视图处理器
//ViewResolvers将逻辑视图转成view对象
initViewResolvers(context);
}
2、主要研究initHandlerMappings(context);方法
/**
* 源码位置:DispatcherServlet#initHandlerMappings(org.springframework.context.ApplicationContext)
* 初始化DispatcherServlet使用的HandlerMappings
*/
private void initHandlerMappings(ApplicationContext context) {
...仅展示主要代码
/**
* 寻找IOC容器中为HandlerMapping类型的Bean
* RequestMappingHandlerMapping便是HandlerMapping的实现类之一
*/
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
/**
* 将HandlerMapping实现类集合赋值给DispatcherServlet的HandlerMappings属性
*/
this.handlerMappings = new ArrayList<>(matchingBeans.values());
/**
* 对找到的HandlerMapping类型的Bean列表进行排序
* 排序后,RequestMappingHandlerMapping排在第一位,首选它
*/
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
二、根据请求查找对应的Controller方法
本小节需要了解以下组件:
HandlerExecutionChain:处理程序执行链,由处理程序对象和任何处理程序拦截器组成。
HandlerMethod:封装由Controller类、Controller类方法组成的信息,提供对方法参数、返回值、注解的便捷访问。
编写一个controller方法,接收 GET localhost:8080/test1/query?pageNum=1&pageSize=2 请求。
1、请求都会经DispatcherServlet#doService()处理。
1.1、在DispatcherServlet#doDispatch()方法中打断点。
/**
* 源码位置: DispatcherServlet#doDispatch(HttpServletRequest, HttpServletResponse)
* 向处理程序分派请求,所有的HTTP方法都由该方法处理。
* 通过HandlerMappings可以获取处理程序。
* 通过HandlerAdapters查询出能解析请求参数的HandlerAdapter
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...仅展示主要代码
/**
* HandlerExecutionChain
* 处理程序执行链,由处理程序对象和任何处理程序拦截器组成。在本次请求中,由Controller方法和拦截器组成
*/
HandlerExecutionChain mappedHandler = null;
/**
* 根据当前request获取handler,handler中包含了请求url,以及对应的controller、controller方法
*/
mappedHandler = getHandler(processedRequest);
// 通过handler获取对应的适配器,adapter负责完成参数解析
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
/**
* 遍历所有定义的 interceptor,执行 preHandle 方法
*/
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 调用目标Controller方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
/**
* 拦截器postHandle方法进行处理
*/
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 处理最后的结果,渲染之类的逻辑都在这里
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
先关注获取HandlerExecutionChain的逻辑
HandlerExecutionChain mappedHandler = null;
mappedHandler = getHandler(processedRequest);
1.1.1、DispatcherServlet#getHandler(HttpServletRequest request)方法解析。
/**
* 源码位置: DispatcherServlet#getHandler(HttpServletRequest request)
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
/**
* 循环this.handlerMappings,遍历得到的第一个mapping是RequestMappingHandlerMapping
* 若HandlerMapping实现类的getHandler()的返回结果不为null,返回此handler
*/
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
1.1.1.1、RequestMappingHandlerMapping.getHandler(HttpServletRequest request)解析
/**
* 源码位置: AbstractHandlerMapping#getHandler(HttpServletRequest request)
* 获取处理器链
*/
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
...仅展示主要代码
//获取handler的具体逻辑由子类实现
Object handler = getHandlerInternal(request);
//根据handler和request构建处理器链HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
return executionChain;
}
1.1.1.1.1、Object handler = getHandlerInternal(request); debug这个方法,最终来到下面的代码中。
/**
* 源码位置: AbstractHandlerMethodMapping#getHandlerInternal(HttpServletRequest request)
*/
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取 request 中的 url,用来匹配 handler
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// 根据路径寻找 Handler,并封装成 HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// 根据 handlerMethod 中的 bean 来实例化 Handler,并添加进 HandlerMethod
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
handlerMethod如下图所示:
1.1.1.1.2、HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);解析。
/**
* 源码位置: AbstractHandlerMapping.getHandlerExecutionChain(Object handler, HttpServletRequest request)
* 构建处理器链HandlerExecutionChain
*/
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//判断handler是不是执行器链,如果不是则创建一个执行器链
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain
? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 添加拦截器
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
回到1.1步骤的代码中:
// 创建处理程序执行链
HandlerExecutionChain mappedHandler = null;
mappedHandler = getHandler(processedRequest);
// 执行拦截器 preHandle 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 执行拦截器postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
这几行代码相信大家已经看懂了。
三、解析请求参数,反射执行Controller方法
解析请求参数
上面分析了通过请求找到对应的Controller方法,接下来分析如何解析请求参数。先了解几个组件:
HandlerAdapter:适配器,包含参数解析、返回值处理等功能。
HandlerMethodArgumentResolver:从request中解析出方法参数。
解析参数的类图如下:
1、在 DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response)处打断点。
/**
* 源码位置: DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response)
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...仅展示主要代码
/**
* 前面已经分析过获取mappedHandler的过程了
*/
/**
* 获取HandlerAdapter
* 最终返回RequestMappingHandlerAdapter
*/
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// controller方法执行,并返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
1.1、HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); 解析
/**
* 源码位置: DispatcherServlet.getHandlerAdapter(Object handler)
* 返回支持当前handler的HandlerAdapter
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
/**
* 遍历所有的 HandlerAdapter,找到和当前 Handler 匹配的HandlerAdapter实例
* 遍历过程中,第一个HandlerAdapter是RequestMappingHandlerAdapter
*
* RequestMappingHandlerAdapter的supports方法代码如下:
* public final boolean supports(Object handler) {
* return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
* }
*
* 通过之前的代码分析得知,请求[ GET localhost:8080/test1/query?pageNum=1&pageSize=2 ]返回的handler是HandlerMethod类型,
* 所以会返回RequestMappingHandlerAdapter
*/
for (HandlerAdapter adapter : this.handlerAdapters) {
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");
}
1.2、mv = ha.handle(processedRequest, response, mappedHandler.getHandler());解析
/**
* 源码位置: RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest request,
* HttpServletResponse response, HandlerMethod handlerMethod)
*/
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//把handlerMethod封装成ServletInvocableHandlerMethod
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
//设置参数解析器
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
//设置返回值处理器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
//设置参数名称发现器
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
//核心逻辑,最终去执行Handler方法处理请求
invocableMethod.invokeAndHandle(webRequest, mavContainer);
return getModelAndView(mavContainer, modelFactory, webRequest);
}
1.2.1、invocableMethod.invokeAndHandle(webRequest, mavContainer);解析
/**
* 源码位置: ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)
* 调用Controller方法并通过HandlerMethodReturnValueHandler处理返回值
*/
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
...仅展示主要代码
// 调用controller中的method方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 处理返回值
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
1.2.1.1、Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);解析
/**
* 源码位置: InvocableHandlerMethod.invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs)
*/
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 获取controller方法实参
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 调用controller方法
return doInvoke(args);
}
1.2.1.1.1、Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);解析
/**
* 源码位置: InvocableHandlerMethod.getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs)
*/
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
...仅展示主要代码
//获取Controller方法参数列表
MethodParameter[] parameters = getMethodParameters();
//创建一个参数数组,保存从request解析出的方法参数
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
//给每一个Controller方法实例参数初始化一个参数名称发现器
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
//解析并绑定参数的核心逻辑
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
return args;
}
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); 这句代码是获取参数值的关键。this.resolvers默认有26个参数解析器。
RequestParamMethodArgumentResolver支持@RequestParam解析,使用request.getParameterValues(name)获取值。
RequestResponseBodyMethodProcessor支持@RequestBody解析,使用MappingJackson2HttpMessageConverter将RequestBody反序列化为javaBean。
1.2.1.2、doInvoke(args);解析
/**
* 源码位置: InvocableHandlerMethod.doInvoke(Object... args)
*/
protected Object doInvoke(Object... args) throws Exception {
...仅展示主要代码
// 方法设置accessible
ReflectionUtils.makeAccessible(getBridgedMethod());
// 调动方法
return getBridgedMethod().invoke(getBean(), args);
}
四、处理返回结果
HandlerMethodReturnValueHandler:处理返回值。
/**
* 源码位置: ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)
* 调用Controller方法并通过 HandlerMethodReturnValueHandler处理返回值
*/
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
...仅展示主要代码
/**
* 前面已经分析了调用controller方法的代码
*/
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
/**
* 现在分析处理返回值的代码
*/
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
1、this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);解析
/**
* 源码位置: HandlerMethodReturnValueHandlerComposite.handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
* 返回值处理
*/
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
/**
* 选择能处理返回值的HandlerMethodReturnValueHandler,通过HandlerMethodReturnValueHandler实现类的supportsReturnType(MethodParameter returnType)判断能否处理返回值
* 例如:RequestResponseBodyMethodProcessor的supportsReturnType(MethodParameter returnType)是判断类或方法有@ResponseBody则返回true
*/
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
/**
* 处理返回值
* RequestResponseBodyMethodProcessor会将Controller方法返回结果写入responseBody。
* 如果Controller方法返回ModelAndView,处理返回值的类是ModelAndViewMethodReturnValueHandler,此类将ModelAndView的属性设置给mavContainer
*/
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
2、回到RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) 方法处。
/**
* 源码位置: RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest request,
* HttpServletResponse response, HandlerMethod handlerMethod)
*/
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
...仅展示部分代码
/**
* 生成ModelAndView
*/
return getModelAndView(mavContainer, modelFactory, webRequest);
}
3、最后对response的处理。
/**
* 源码位置: DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response)
* 处理最后的结果
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...仅展示部分代码
// 处理最后的结果,渲染之类的逻辑都在这里
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}