- 1、SpringMVC请求处理流程
- 2、DispatcherServlet
- 3、HandlerMapping组件
- 4、HandlerAdapter组件
SpringMVC的核心组件和请求处理流程如下:
-
1、 DispatcherServlet是SpringMVC中的前端控制器(front controller),负责接收request并将request转发给对应的处理组件。
-
2、HanlerMapping是SpringMVC中完成url到Controller映射的组件。DispatcherServlet接收request,然后从HandlerMapping查找处理request的controller.
-
3、Cntroller处理request,并返回ModelAndView对象,Controller是SpringMVC中负责处理request的组件(类似于struts2中的Action),ModelAndView是封装结果视图的组件。
-
4、视图解析器解析ModelAndView对象并返回对应的视图给客户端。
前端控制器,也是处理请求开始的地方,先看一下它的结构,然后在逐一分析里面的不同组件。
- 可以看到它是继承了HttpServlet的,用来接收请求的。
- 也是实现了ApplicationContextAware接口的可以猜到它是用来获取需要的相关组件的。
我们进去它的父类frameworkServlet会看到Servlet在初始化的时候会给Spring注册一个容器刷新的监听事件,在容器初始化完之后会进来刷新执行初始化操作。
onRefresh则是从容器中获取需要的相关组件,比如MultipartResolver、HandlerMappings、HandlerAdapters等组件。
处理请求的位置则是在org.springframework.web.servlet.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);
// 1、根据请求找到对应的控制器执行器链HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2、找到对应控制器的适配器,用来执行操作的
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;
}
// 正在执行控制器逻辑
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) {
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);
}
}
}
}
DispatcherServlet的大概流程和原理就是这样,但是只看这个基本跟没看没区别,所以我们需要去了解里面的主要的几种组件的原理。
本文只分析了HandlerMapping、HandlerAdapter两种组件。
3、HandlerMapping组件这里只针对RequestMappingHandlerMapping这个处理器映射器解析,它就是处理@Controller、@RequestMapping等注解的组件了。先看一下它的组成结构,然后再逐一分析它的每一个接口或者抽象类的功能。
可以看到接口功能类型分两类:
- 第一部分是Spring容器的扩展支持
- 第二部分就是HandlerMapping的功能实现了。
第一部分就是在设置SpringContext的时候执行初始化的功能,从源码可以清楚的看到就是扩展、初始化、判断包装了一下拦截器而已。
重点还是在第二部分,我会根据接口的继承层次一个一个分别讲解。
1、先看HandlerMapping接口,在这个接口中只定义了一个规范,就是接受一个请求返回一个控制器的执行链。
public interface HandlerMapping {
....略
@Nullable
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
在HandlerExecutionChain里面包含了handler、拦截器等主要属性。
其中handler在不同的处理器映射器中存的对象不同,就是具体的执行对象了。在RequestMappingHandlerMapping中存的就是HandlerMethod
拦截器的功能则是在applyPreHandle、applyPostHandle、triggerAfterCompletion、applyAfterConcurrentHandlingStarted这些方法中执行。
2、接着在基础抽象类AbstractHandlerMapping看一下getHandler的处理逻辑。
这一步会有子类去getHandlerInternal获取handler,如果是String的话会当做BeanName去容器中获取具体的对象。
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 获取内部的handler,由子类去实现
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 拿到handler之后就去获取HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
// 如果有cors则去获取
if (hasCorsConfigurationSource(handler)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
// 最后返回
return executionChain;
}
其中getHandlerExecutionChain根据url找出匹配的拦截器放进去,然后再返回。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 获取url
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
// 从已经有的拦截器判断是否MappedInterceptor,如果是则需要匹配路径,不是则默认拦截
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;
}
至于getHandlerInternal方法由子类实现,先不讲,后面讲到的了继续分析。
3、接着看AbstractHandlerMethodMapping
在属性设置完之后会去初始化handlerMethods在processCandidateBean方法中会判断如果类有@Controller、@RequestMapping直接就会去detectHandlerMethods。
protected void detectHandlerMethods(Object handler) {
// 如果是String当做类型去容器中获取
Class> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class> userType = ClassUtils.getUserClass(handlerType);
// 循环类的每一个方法,获取方法对应Mapping信息
Map methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.metadataLookup) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
// 然后注册进mappingRegistry中
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
在detectHandlerMethods中的逻辑主要就是:
- 获取每个方法对象MappingInfo信息,其中getMappingForMethod(method, userType)是由子类去实现的。
- registerHandlerMethod则是将Method 、handler、mapping注册到MappingRegistry中。
需要注意的是这一步的handler可以是beanName也可以是具体的Bean(也就是Controller)。
4、接着看RequestMappingInfoHandlerMapping,这个抽象类主要是做RequestMappingInfo的匹配判断比较逻辑的。
主要需要了解的是RequestMappingInfo的组成。
如果你看了@RequestMapping注解的话,你就会发现这里就是存了url的匹配条件。
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] consumes() default {};
String[] produces() default {};
}
上面已经扫描的Bean然后解析了MappingInfo信息,还有一个接口就是getHandlerInternal从已经注册的缓存中获取HandlerMethod。
5、最后看RequestMappingHandlerMapping这里比较核心的方法有:
-
isHandler:判断handler类型
-
createRequestMappingInfo:解析注解构建RequestMappingInfo
组成大概就这些,我们直接debug进去看下最后RequestMappingHandlerMapping最终获取的HandlerExecutionChain的组成:
- 拦截器集合
- HandlerMethod:包括控制层对象、这个请求匹配的方法、方法参数等信息。
总的来说,RequestMapping就是解析url并注册记录,然后负责根据请求匹配到某个具体的执行对象。
获取到了对应的handler之后就是执行这个handler了,就交给了HandlerAdapter适配器来执行,并且处理返回结果。
先看一下它的接口定义了哪些规范。
public interface HandlerAdapter {
// 判断支持的handler
boolean supports(Object handler);
// 执行handler并且返回结果。
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
// 根据handler决定是否需要修改request
long getLastModified(HttpServletRequest request, Object handler);
}
第一个的话就是判断支持对象了:
具体的执行方法:
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 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 mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
就是解析参数,执行具体对象的方法,然后根据返回类型返回详情数据。其他的看累了,先不写了。



