一、引言:
如下是我画的一个简单的SpringMVC的请求流程图,接下来会通过请求流程图去进行源码分析。
- [1 ] 当我们客户端发送请求时,Servlet会进行请求的解析,然后交给DispatcherServlet进行统一分发。
- [2] DispatcherServlet会根据我们的请求路径去寻找对应的HandlerMapping,并返回一个HandlerExecutionChain(如果没有寻找到也就会返回404)
HandlerExecutionChain: 请求处理链,包括请求处理器和处理器拦截器等。它的作用是在请求处理过程中,按照一定的顺序调用各个处理器,确保在请求处理器执行前后,能够按照需要进行预处理和后处理。
- [3] 根据请求的HandlerMapping去适配HandlerAdapter。
- [4] DispatcherServlet 调用拦截器的PreHandl,这个是在之前方法之前调用。
- [5] DispatcherServlet执行我们请求路径的方法,请求完成后返回一个返回ModelAndView。
- [6] DispatcherServlet将ModelAndView传给ViewReslover视图解析器,ViewReslover解析后返回具体的View视图(JSP / HTML)。
- [7] DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
- [8] DispatcherServlet响应用户,用户看到界面和数据。
源码分析:
- 当我们接收到请求时,先执行FrameworkServlet里面的Service方法
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 解析请求
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
// 在执行HttpServlet的service()方法
super.service(request, response);
} else {
this.processRequest(request, response);
}
}
- 在执行HttpServlet的service()方法
这里主要看你是什么请求,post请求就走dopost方法,get请求就走doget方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
。。。。。。
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
- 调用processRequest()方法
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = this.buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
this.initContextHolders(request, localeContext, requestAttributes);
try {
// 在调用doService方法
this.doService(request, response);
} catch (IOException | ServletException var16) {
failureCause = var16;
throw var16;
} catch (Throwable var17) {
failureCause = var17;
throw new NestedServletException("Request processing failed", var17);
} finally {
this.resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
this.logResult(request, response, (Throwable)failureCause, asyncManager);
this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
}
}
- doService()方法
进行请求处理的前置准备。
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.logRequest(request);
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration<?> attrNames = request.getAttributeNames();
label116:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label116;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
// 把spring容器,相关一些信息存入request当中
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
// 重定向,转发
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
RequestPath previousRequestPath = null;
if (this.parseRequestPath) {
previousRequestPath = (RequestPath)request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
ServletRequestPathUtils.parseAndCache(request);
}
try {
// 核心方法
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
if (this.parseRequestPath) {
ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
}
}
}
5.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 {
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 寻找对应查找对应请求路径,是否存在,返回对象或者方法
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
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;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
处理HandlerMapping
方法调用流程图如下
mappedHandler = this.getHandler(processedRequest);
在这里就是寻找对应请求是否存在,比如我是用RequestMapping注解进行请求的。如果请求不存在就直接返回404了
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
// 遍历DisparchServlect.properties文件中的HandlerMapping
// BeanNameUrlHandlerMapping 优先级最高
// RequestMappingHandlerMapping
// RouterFunctionMapping
while(var2.hasNext()) {
// 使用策略模式
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
mapping.getHandler(request);
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
}
getHandlerInternal()方法
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = this.initLookupPath(request);
this.mappingRegistry.acquireReadLock();
HandlerMethod var4;
try {
// 这里就是在我们mappingRegistry中取出对应的请求方法进行返回
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
} finally {
this.mappingRegistry.releaseReadLock();
}
return var4;
}
适配HandlerAdapter:
方法调用流程图如下
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
这里也是通过DispatcherServlet.properties文件中获取HandlerAdapter,根据我们不同请求的HandlerMapping去适配对应的HandlerAdapter。
因为如果我们实现Controller接口他相应的请求就是BeanNameUrlHandlerMapping。而这个请求他在处理我们HandlerMapping时,是只需要返回一个对象参数在进行接口回调即可。
@Component("/test")
public class Test implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return null;
}
}
而我们如果是使用RequstMapping注解呢,该注解是制定某个方法进行请求,而不是指定每个类请求。所以这个请求处理我们HandlerMapping时,返回的就是一个方法,那么他接收请求处理的方式又不一样。所以这时候就需要我们的HandlerAdapter来进行适配。
源码分析
getHandlerAdapter(Object handler)
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
// 1.HttpRequestHandlerAdapter
// 2.SimpleControllerHandlerAdapter
// 3.RequestMappingHandlerAdapter
// 4.HandlerFunctionAdapter
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
if (adapter.supports(handler)) {
return adapter;
}
}
}
如果你是BeanNameUrlHandlerMapping 请求,那么就会适配SimpleControllerHandlerAdapter,调用supports方法。看你当前handler 是否实现Controller接口
public boolean supports(Object handler) {
return handler instanceof Controller;
}
如果你是RequestMappingHandlerMapping请求,那么就会适配AbstractHandlerMethodAdapter,调用supports方法。看你当前handler 是否是一个方法。
public final boolean supports(Object handler) {
return handler instanceof HandlerMethod && this.supportsInternal((HandlerMethod)handler);
}
前置拦截器处理:
这里会去循环遍历interceptorList里面的拦截器,然后根据特定拦截器执行前置方法。如果方法返回false,则流程结束。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
List<HandlerInterceptor> interceptorList;
执行方法handle():
- 创建binderFactory 作用于@InitBinder注解的方法
- 创建modelFactory 创建model对象,作用于@ModelAttribute
- 设置方法参数解析器,返回值解析器。 这些解析器都是在初始化HandlerAdapter时会进行创建加载。
- 初始化model对象,在设置model的其他属性值。
- 调用invokeAndHandle执行方法(1.用适配器去解析相应的方法参数解析器;2.执行方法;3.用适配器去适配结果返回值处理器)
- 返回ModelAndView
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 获取方案参数
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return this.doInvoke(args);
}
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 获取当前方法有那些参数
MethodParameter[] parameters = this.getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} else {
Object[] args = new Object[parameters.length];
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
// 获取相应的参数解析器
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 对该参数进行赋值
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var10) {
if (logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
}
return args;
}
}
视图渲染():
mappedHandler.applyPostHandle(processedRequest, response, mv);
这里源码就不在进行分析了,主要就是通过执行完方法返回的ModelAndView进行适配视图解析器viewResolver,最后在进行视图的渲染。
方法总体调用图:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
throws Exception {
...
//1、根据URL(当然不一定非得是URL)匹配到一个处理器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 若匹配不到Handler处理器,就404了
noHandlerFound(processedRequest, response);
return;
}
//2、从HandlerExecutionChain里拿出Handler(注意是Object类型哦~ )然后找到属于它的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
//3、执行作用在此Handler上的所有拦截器的Pre方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//4、真正执行handle方法(也就是你自己书写的逻辑方法),得到一个ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//5、视图渲染
applyDefaultViewName(processedRequest, mv);
//6、执行拦截器的post方法(可见它是视图渲染完成了才会执行的哦~)
mappedHandler.applyPostHandle(processedRequest, response, mv);
...
//7、执行拦截器的afterCompletion方法(不管抛出与否)
}
总结:
1.客户端发起请求,请求被DispatcherServlet接收。
2.DispatcherServlet把请求交给HandlerMapping解析器进行映射,得到匹配的Controller。
3.Controller接收到请求后进行处理,把处理结果放到Model中返回给DispatcherServlet。
4.DispatcherServlet把Model交给ViewResolver视图解析器,找到对应的视图。
5.视图渲染处理,最终生成HTML页面返回给客户端。