DispatcherServlet 是什么
概述 :
::: DispatcherServlet
作为Spring MVC的核心控制器,初始化组件,处理客户端发送的请求,并返回 ModelAndView
,进行视图渲染。主要是实现了父类 FrameworkServlet
的抽象方法 doService()
。
:::
DispatcherServlet 类图
DispatcherServlet
的initStrategies
方法如何被调用的入口类:
AbstractApplicationContext
#refresh
├─
refresh
│├─
finishRefresh
││└─
publishEvent
│││├─
publishEvent
│││└─
multicastEvent
││││└─
invokeListener
│││││└─
doInvokeListener
││││││└─
onApplicationEvent
│││││││└─
onRefresh
││││││││└─
onRefresh
│││││││││└─
initStrategies进入
onRefresh
方法所在类:org.springframework.web.servlet.
DispatcherServlet
-
protected void onRefresh(ApplicationContext context) {
-
initStrategies(context);
-
}
-
protected void initStrategies(ApplicationContext context) {
-
// 初始化文件上传处理
-
initMultipartResolver(context);
-
// 初始化本地化 Resolver
-
initLocaleResolver(context);
-
// 初始化主题 Resolver
-
initThemeResolver(context);
-
// 初始化 URL映射关系
-
initHandlerMappings(context);
-
// 初始化Handler接口适配器
-
initHandlerAdapters(context);
-
// 初始化异常处理的 handler
-
initHandlerExceptionResolvers(context);
-
// 初始化请求路径转换
-
initRequestToViewNameTranslator(context);
-
// 初始化视图解析
-
initViewResolvers(context);
-
// 初始化 flashmap管理
-
initFlashMapManager(context);
-
}
::: warning 知识点 initStrategies
方法中的所有初始化组件中之所以可以拿到值,主要是通过 @EnableWebMvc
注解,调用到 WebMvcConfigurationSupport
类中的各个 @Bean
注解的方法,完成的实例化过程。:::
请求调用流程
当父子容器都启动完成后,开始进行请求的响应处理,
- 请求
http://localhost:9090/user/queryUser
地址
进入
service
方法所在类:javax.servlet.http.
HttpServlet
-
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
String method = req.getMethod();
-
long lastModified;
-
if (method.equals("GET")) {
-
lastModified = this.getLastModified(req);
-
if (lastModified == -1L) {
-
this.doGet(req, resp);
-
}
-
// ...... 省略
-
}
进入
doGet
方法所在类:org.springframework.web.servlet.
FrameworkServlet
-
@Override
-
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
-
throws ServletException, IOException {
-
processRequest(request, response);
-
}
进入
processRequest
方法所在类:org.springframework.web.servlet.
FrameworkServlet
-
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
-
throws ServletException, IOException {
-
long startTime = System.currentTimeMillis();
-
Throwable failureCause = null;
-
doService(request, response);
-
}
进入
doService
方法所在类:org.springframework.web.servlet.
DispatcherServlet
-
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
-
logRequest(request);
-
try {
-
// 调用核心流程
-
doDispatch(request, response);
-
}
-
finally {
-
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
-
// Restore the original attribute snapshot, in case of an include.
-
if (attributesSnapshot != null) {
-
restoreAttributesAfterInclude(request, attributesSnapshot);
-
}
-
}
-
}
-
}
请求调用 核心入口
请求最终进入
doDispatch
方法所在类:org.springframework.web.servlet.
DispatcherServlet
-
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 {
-
// 文件上传解析,如果请求类型是multipart将通过
-
// MultipartResolver进行文件上传解析
-
processedRequest = checkMultipart(request);
-
multipartRequestParsed = (processedRequest != request);
-
// 对当前请求匹配一个合适的 handler,重要方法
-
mappedHandler = getHandler(processedRequest);
-
if (mappedHandler == null) {
-
noHandlerFound(processedRequest, response);
-
return;
-
}
-
// Determine handler adapter for the current request.
-
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) {
-
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 {
-
// 如果是multipart的请求,清空上传的multipart资源
-
if (multipartRequestParsed) {
-
cleanupMultipart(processedRequest);
-
}
-
}
-
}
-
}
::: warning 知识点总结, getHandler
方法的主要作用体现在以下几点:
-
首先,从当前Request中拿到请求的
URL
-
然后,从映射关系中拿到
HandlerMethod
对象 -
接着,把
HandlerMethod
对象封装到HandlerExecutionChain
执行链中 -
最后,在
HandlerExecutionChain
执行链的创建过程中会拿到整个容器中所有的拦截器(实现HandlerInterceptor
接口的拦截器),和当前请求的URL
进行匹配,如果匹配成功的话,就会把拦截器放到HandlerExecutionChain
的数组中。:::
进入
getHandler
方法所在类:org.springframework.web.servlet.
DispatcherServlet
-
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
-
// handlerMappering 实例容器不为空
-
if (this.handlerMappings != null) {
-
for (HandlerMapping mapping : this.handlerMappings) {
-
// 获取 HandlerMethod 和过滤器链的包装类
-
HandlerExecutionChain handler = mapping.getHandler(request);
-
if (handler != null) {
-
return handler;
-
}
-
}
-
}
-
return null;
-
}
进入
getHandler
方法所在类:org.springframework.web.servlet.handler.
AbstractHandlerMapping
-
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
-
// 根据请求的 URL 拿到对应的 HandlerMethod 对象
-
Object handler = getHandlerInternal(request);
-
if (handler == null) {
-
handler = getDefaultHandler();
-
}
-
if (handler == null) {
-
return null;
-
}
-
// Bean name or resolved handler?
-
if (handler instanceof String) {
-
String handlerName = (String) handler;
-
handler = obtainApplicationContext().getBean(handlerName);
-
}
-
// 获取 HandlerMethod 和过滤器链的包装类
-
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());
-
}
-
// 是否是跨域请求,就是查看 request 请求头中是否有 Origin 属性
-
if (CorsUtils.isCorsRequest(request)) {
-
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
-
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
-
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
-
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
-
}
-
return executionChain;
-
}
进入
getHandlerInternal
方法所在类:org.springframework.web.servlet.handler.
AbstractHandlerMethodMapping
-
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
-
// 从request对象中获取 URL,/common/query2
-
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
-
this.mappingRegistry.acquireReadLock();
-
try {
-
// 根据 URL 从映射关系中找到对应的 HandlerMethod 对象
-
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
-
// 执行beanFactory.getBean的过程,获取Controller实例
-
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
-
}
-
finally {
-
this.mappingRegistry.releaseReadLock();
-
}
-
}
::: warning 知识点
lookupHandlerMethod
方法之所以可以从映射关系中拿到 HandlerMethod
对象,是因为 AbstractHandlerMethodMapping
类实现了 InitializingBean
接口,在 afterPropertiesSet
方法里建立好了映射关系。:::
进入
lookupHandlerMethod
方法所在类:org.springframework.web.servlet.handler.
AbstractHandlerMethodMapping
-
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
-
List<Match> matches = new ArrayList<>();
-
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
-
if (directPathMatches != null) {
-
// 匹配过程,是否符合 RequestMappingInfo 里的属性值
-
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);
-
// 如果两个 RequestMappinginfo 什么都相同,报错
-
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);
-
return bestMatch.handlerMethod;
-
}
-
else {
-
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
-
}
-
}
**::: warning 知识点 **
addMatchingMappings
方法,主要一个匹配过程,匹配 @RequestMapping
注解中的属性值是否满足
-
/*
-
* consumes:指定处理请求的提交内容类型(Content-Type),
-
* 例如application/json, text/html;
-
* produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
-
* params:指定request中必须包含某些参数值是,才让该方法处理。
-
* headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。
-
* */
-
@RequestMapping(value = "/getUser",
-
method = RequestMethod.GET,
-
params = "username=jack",
-
consumes = "application/json",
-
produces = "application/json",
-
headers = "Referer=http://www.xx.com/")
:::
返回
getHandler
,进入getHandlerExecutionChain
方法所在类:org.springframework.web.servlet.handler.
AbstractHandlerMapping
-
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
-
// 如果没有获得则创建一个 HandlerExecutionChain
-
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
-
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
-
// 获取当前的请求地址:/user/xxx
-
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
-
// 在 HandlerExecutionChain 中添加拦截器
-
// 遍历 SpringMVC 容器的所有拦截器
-
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
-
// 判断拦截器类型,如果是 MappedInterceptor 类型
-
if (interceptor instanceof MappedInterceptor) {
-
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
-
// 则先匹配路径后再添加到执行链
-
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
-
chain.addInterceptor(mappedInterceptor.getInterceptor());
-
}
-
}
-
else {
-
// 否则直接添加到执行链
-
chain.addInterceptor(interceptor);
-
}
-
}
-
return chain;
-
}
**::: warning 知识点 **
getHandlerExecutionChain
中的 HandlerInterceptor
拦截器是 SpringMVC
中的, SpringAOP
中的拦截器是 MethodInterceptor
。:::
拿到当前请求对应的
handler
后,返回主流程,进入
getHandlerAdapter
方法所在类:org.springframework.web.servlet.
DispatcherServlet
-
/**
-
* TODO : 根据 handlerMethod对象,找到合适的 HandlerAdapter对象,这里用到了策略模式
-
*/
-
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
-
if (this.handlerAdapters != null) {
-
for (HandlerAdapter adapter : this.handlerAdapters) {
-
if (adapter.supports(handler)) {
-
// 返回一个可以支持的HandlerAdapter 处理程序实例
-
return adapter;
-
}
-
}
-
}
-
throw new ServletException("No adapter for handler [" + handler +
-
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
-
}
::: warning 知识点
HandlerAdapter
是什么HandlerAdapter
是一个接口,充当自身与处理程序对象之间的桥梁,从而导致松散耦合设计。HandlerAdapter
主要处理方法参数、相关注解、数据绑定、消息转换、返回值、调用视图解析器等。
RequestMappingHandlerMapping
为当前的请求找到合适的处理程序方法。
RequestMappingHandlerAdapter
执行这个处理程序方法,并为它提供反射调用所需要的参数。
HandlerAdapter
UML 图
HandlerAdapter
的4个实现类:
SimpleServletHandlerAdapter
: 适配实现Servlet
接口的Handler
, 默认调用其service
方法
SimpleControllerHandlerAdapter
: 适配实现Controller
接口的Handler
, 默认调用其handleRequest
方法
HttpRequestHandlerAdapter
: 适配实现HttpRequestHandler
接口的Handler
, 默认调用其handleRequest
方法
RequestMappingHandlerAdapter
: 适配被@RequestMapping
注释的方式, 一般都是解析一个一个参数, 并且通过反射进行激活
HandlerAdapter
总结HandlerAdapter
是SpringMVC
中扩展机制的非常好的一个体现,,通过HandlerAdapter
这种设计模式,DispatcherServlet
就可以支持任何格式的Handler
(这里的可以支持指在不改变 DispatcherServlet 的情况下),第二是HandlerAdapter
基于不同Handler
实现不同实现类(策略模式),最后也是最重要的就是参数的解析与返回值的解析。
:::
::: danger 为什么要用HandlerAdapter适配器模式? 首先, Controller
的定义有多种 ,一种是带 @Controller
注解的, 还可以写一个 servlet
当做 controller
, 所以用适配器做适配,不同子类实现 HandlerAdapter
接口,定义自己的业务逻辑,每个子类都是适配某一种类型的控制器,有了 HandlerAdapter
,你只需要调用自己实现的 handle
方法,屏蔽了不一致的细节,对用户来说直接找到对应的处理方法,无须关系哪个实现方法,否则只能在 DispatcherServlet
里面通过 if
、 else
来处理了。:::
前置过滤器
返回主流程,进入
applyPreHandle
方法,前置过滤器所在类:org.springframework.web.servlet.
DispatcherServlet
-
/**
-
* TODO :调用所有的 HandlerInterceptor 拦截器并调用其 preHandler方法
-
*/
-
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
-
// 获取所有的拦截器
-
HandlerInterceptor[] interceptors = getInterceptors();
-
if (!ObjectUtils.isEmpty(interceptors)) {
-
for (int i = 0; i < interceptors.length; i++) {
-
HandlerInterceptor interceptor = interceptors[i];
-
// 分别调用拦截器的 preHandle 方法
-
if (!interceptor.preHandle(request, response, this.handler)) {
-
triggerAfterCompletion(request, response, null);
-
return false;
-
}
-
// 如果失败,记录最后一次拦截器的位置,倒序释放
-
this.interceptorIndex = i;
-
}
-
}
-
return true;
-
}
返回主流程,进入
handle
方法,调用具体Controller
的方法最终会进入
AbstractHandlerMethodAdapter
的handle
方法,
-
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
-
throws Exception {
-
return handleInternal(request, response, (HandlerMethod) handler);
-
}
进入
handleInternal
方法,所在类:org.springframework.web.servlet.mvc.method.annotation.
RequestMappingHandlerAdapter
-
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) {
-
HttpSession session = request.getSession(false);
-
if (session != null) {
-
Object mutex = WebUtils.getSessionMutex(session);
-
synchronized (mutex) {
-
mav = invokeHandlerMethod(request, response, handlerMethod);
-
}
-
}
-
else {
-
// No HttpSession available -> no mutex necessary
-
// 执行 HandlerMethod,返回 ModelAndView
-
mav = invokeHandlerMethod(request, response, handlerMethod);
-
}
-
}
-
else {
-
// No synchronization on session demanded at all...
-
// 执行 HandlerMethod,返回 ModelAndView
-
mav = invokeHandlerMethod(request, response, handlerMethod);
-
}
-
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
-
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
-
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
-
}
-
else {
-
prepareResponse(response);
-
}
-
}
-
return mav;
-
}
进入
invokeHandlerMethod
方法,所在类:org.springframework.web.servlet.mvc.method.annotation.
RequestMappingHandlerAdapter
-
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
-
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
-
ServletWebRequest webRequest = new ServletWebRequest(request, response);
-
try {
-
// 获取数据绑定工厂 @InitBinder注解支持,
-
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
-
// Model工厂,收集了@ModelAttribute注解的方法
-
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));
-
// 调用有 @ModelAttribute注解的方法。每次请求都会调用有 @ModelAttribute注解的方法
-
//把 @ModelAttribute注解的方法的返回值存储到 ModelAndViewContainer对象的 map中了
-
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);
-
}
-
// Controller方法调用,重点看看
-
invocableMethod.invokeAndHandle(webRequest, mavContainer);
-
if (asyncManager.isConcurrentHandlingStarted()) {
-
return null;
-
}
-
return getModelAndView(mavContainer, modelFactory, webRequest);
-
}
-
finally {
-
webRequest.requestCompleted();
-
}
-
}
::: warning 知识点
invokeHandlerMethod
方法主要进行了数据和参数的绑定、创建 ModelAndViewContainer
视图容器,以及相关初始化工作。:::
进入
invokeAndHandle
方法所在类:org.springframework.web.servlet.mvc.method.annotation.
ServletInvocableHandlerMethod
-
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
-
Object... providedArgs) throws Exception {
-
// 具体调用逻辑,重点看
-
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
-
setResponseStatus(webRequest);
-
if (returnValue == null) {
-
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
-
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) {
-
if (logger.isTraceEnabled()) {
-
logger.trace(formatErrorForReturnValue(returnValue), ex);
-
}
-
throw ex;
-
}
-
}
进入
invokeForRequest
方法所在类:org.springframework.web.method.support.
InvocableHandlerMethod
-
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);
-
}
进入
getMethodArgumentValues
方法所在类:org.springframework.web.method.support.
InvocableHandlerMethod
-
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
-
Object... providedArgs) throws Exception {
-
if (ObjectUtils.isEmpty(getMethodParameters())) {
-
return EMPTY_ARGS;
-
}
-
// 入参的包装类,里面包装了参数类型,参数名称,参数注解等等信息
-
MethodParameter[] parameters = getMethodParameters();
-
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) {
-
continue;
-
}
-
// 典型的策略模式,根据 parameter 能否找到对应参数的处理类,能找到就返回true
-
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 ex) {
-
// Leave stack trace for later, exception may actually be resolved and handled..
-
if (logger.isDebugEnabled()) {
-
String error = ex.getMessage();
-
if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
-
logger.debug(formatArgumentError(parameter, error));
-
}
-
}
-
throw ex;
-
}
-
}
-
return args;
-
}
进入
resolveArgument
方法所在类:org.springframework.web.method.support.
HandlerMethodArgumentResolverComposite
-
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
-
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
-
// 根据参数获取对应参数的解析类
-
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
-
if (resolver == null) {
-
throw new IllegalArgumentException(
-
"Unsupported parameter type [" + parameter.getParameterType().getName() + "]." +
-
" supportsParameter should be called first.");
-
}
-
// 策略模式去调用具体参数解析类
-
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
-
}
::: warning 知识点
MethodParameter
类是对参数信息的封装,其中重要的几个属性包括:
-
parameterIndex
:参数的索引位置 -
Parameter
:具体参数的对象,包含参数名字 -
parameterType
:参数的类型 -
parameterAnnotations
:参数的注解数组,一个参数可以有多个注解 -
parameterName
:参数名 等等 :::
方法参数解析
进入
getArgumentResolver
方法所在类:org.springframework.web.method.support.
HandlerMethodArgumentResolverComposite
-
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
-
// 先从缓存中拿到参数处理器对象
-
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
-
// 如果缓存中没有
-
if (result == null) {
-
// 循环容器中 HandlerMethodArgumentResolver类型的所有解析器: List<HandlerMethodArgumentResolver>
-
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
-
// 典型的策略模式匹配,拿到当前参数对应的处理解析类
-
if (methodArgumentResolver.supportsParameter(parameter)) {
-
// 赋值给 HandlerMethodArgumentResolver 对象
-
result = methodArgumentResolver;
-
// 放到缓存中
-
this.argumentResolverCache.put(parameter, result);
-
break;
-
}
-
}
-
}
-
return result;
-
}
::: warning 知识点
HandlerMethodArgumentResolver
参数解析器,最复杂的处理流程之一,Spring中默认有26种参数解析器,来对应完成某种参数的解析工作。添加过程是 SpringMVC
启动实例化后,通过 RequestMappingHandlerAdapter
类的 afterPropertiesSet
方法调用 getDefaultArgumentResolvers
添加到 HandlerMethodArgumentResolver
解析器中的。:::
中置过滤器
返回主流程,进入
handleInternal
方法,中置过滤器所在类:org.springframework.web.servlet.mvc.method.annotation.
RequestMappingHandlerAdapter
-
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
-
throws Exception {
-
// 获取所有拦截器
-
HandlerInterceptor[] interceptors = getInterceptors();
-
if (!ObjectUtils.isEmpty(interceptors)) {
-
for (int i = interceptors.length - 1; i >= 0; i--) {
-
HandlerInterceptor interceptor = interceptors[i];
-
// 分别调用拦截器的 postHandle方法
-
interceptor.postHandle(request, response, this.handler, mv);
-
}
-
}
-
}
::: warning 知识点中置过滤器的调用时序,是当 ha.handle
掉完以后,也就是 Controller
里面具体方法调用完以后才轮到中置过滤器调用。可以根据 ModelAndView
对象做视图修改。:::
后置过滤器
返回主流程,进入
triggerAfterCompletion
方法,后置过滤器所在类:org.springframework.web.servlet.mvc.method.annotation.
RequestMappingHandlerAdapter
-
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
-
throws Exception {
-
HandlerInterceptor[] interceptors = getInterceptors();
-
if (!ObjectUtils.isEmpty(interceptors)) {
-
for (int i = this.interceptorIndex; i >= 0; i--) {
-
HandlerInterceptor interceptor = interceptors[i];
-
try {
-
interceptor.afterCompletion(request, response, this.handler, ex);
-
}
-
catch (Throwable ex2) {
-
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
-
}
-
}
-
}
-
}
::: warning 知识点
applyPreHandle
前置过滤器主要作用是对当前请求做一些初步的验证,内部执行顺序是正序遍历, applyPostHandle
中置过滤器和 triggerAfterCompletion
后置过滤器的执行顺序是倒序遍历,倒序是因为一但前置过滤器中断(拦截器 preHndle
返回 false
)那么请求终止,根据中断的数组坐标 interceptorIndex
,倒序释放执行已经过滤的的拦截方法。:::
到此为止,主流程结束,以上完成了Spring MVC`从请求到处理的一系列过程,包括请求方法调用
、参数解析、过滤器调用等,接下来就是处理返回值的解析工作。
附:常见注解
::: danger 常见注解
-
@ModelAttribute:会在调用Controller的每个方法执行前被执行。
-
@RequestBody:用来处理
content-type
为application/json
的类型,可以是对象。 -
@ResponseBody:一般用于返回 JSON 或 XML 数据。
-
@RequestPart:用来处理
content-type
为multipart/form-data
类型的表单提交请求。 -
@ExceptionHandler:用在方法上,在运行时有效,只捕获当前Controller 中发生的异常。
-
@ControllerAdvice:用在类上,@ControllerAdvice(“com.xx.xx”)只对这个包里 面的 Controller 生效,并将该类中所有使用了
@ExceptionHandler
注解的方法都应用到请求处理方法上。 -
@Cacheable:若该缓存中没有存储该条记录,则执行该方法,有则从缓存取。
-
@CacheEvict:将该缓存下的所有记录都清空。
-
@CachePut:总是会执行该方法,每次都把返回结果更新进该缓存中。
-
@RequestParam:适用于所有类型的参数;
-
@RequestHeader:用于将请求头的信息数据映射到方法参数上 。
-
@CookieValue:用于将请求的 cookie 数据映射到功能处理方法的参数上。
-
@InitBinder:用于绑定表单数据的注解。
-
@RequestAttribute:用于获取 request作用域 中的数据。
-
@SessionAttribute:用于获取 session作用域中的数据。
-
@PathVariable:获取请求 URL 中的动态参数(路径参数),如:“/test4/{id}/{name}”。
-
@MatrixVariable:扩展了URL请求地址,多个请求参数可用
,
分开, 一般用于进行多条件的组合查询。 -
@CrossOrigin:用于不同域名访问,解决跨域问题。
#结尾
来源: 享学课堂online
今天就说到这里啦
[图片上传中…(image.png-38cb79-1598169870635-0)]
最后
小编这些年深知大多数初中级工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Java全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你需要这些资料,⬅专栏获取
@RequestBody:用来处理 content-type
为 application/json
的类型,可以是对象。
-
@ResponseBody:一般用于返回 JSON 或 XML 数据。
-
@RequestPart:用来处理
content-type
为multipart/form-data
类型的表单提交请求。 -
@ExceptionHandler:用在方法上,在运行时有效,只捕获当前Controller 中发生的异常。
-
@ControllerAdvice:用在类上,@ControllerAdvice(“com.xx.xx”)只对这个包里 面的 Controller 生效,并将该类中所有使用了
@ExceptionHandler
注解的方法都应用到请求处理方法上。 -
@Cacheable:若该缓存中没有存储该条记录,则执行该方法,有则从缓存取。
-
@CacheEvict:将该缓存下的所有记录都清空。
-
@CachePut:总是会执行该方法,每次都把返回结果更新进该缓存中。
-
@RequestParam:适用于所有类型的参数;
-
@RequestHeader:用于将请求头的信息数据映射到方法参数上 。
-
@CookieValue:用于将请求的 cookie 数据映射到功能处理方法的参数上。
-
@InitBinder:用于绑定表单数据的注解。
-
@RequestAttribute:用于获取 request作用域 中的数据。
-
@SessionAttribute:用于获取 session作用域中的数据。
-
@PathVariable:获取请求 URL 中的动态参数(路径参数),如:“/test4/{id}/{name}”。
-
@MatrixVariable:扩展了URL请求地址,多个请求参数可用
,
分开, 一般用于进行多条件的组合查询。 -
@CrossOrigin:用于不同域名访问,解决跨域问题。
#结尾
来源: 享学课堂online
今天就说到这里啦
[图片上传中…(image.png-38cb79-1598169870635-0)]
最后
小编这些年深知大多数初中级工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Java全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-dmzUhZKu-1719526859809)]
[外链图片转存中…(img-GxPYud2z-1719526859809)]
[外链图片转存中…(img-COibl7TM-1719526859810)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你需要这些资料,⬅专栏获取