a、http请求是怎么被Controller接受处理,然后返回结果的?
发出HTTP请求后,跳过网络层的东西,当被应用服务器Tomcat接受的时候。在Tomcat中存在一个servlet容器,它负责管理所有的servlet,包括SpringMVC的核心组件DispatcherServlet。
请求进入到HttpServlet的service方法中后。service方法会根据 HTTP 请求是 GET、POST、PUT 还是 DELETE 等,进一步调用 Servlet 的 doGet(),doPost(),doPut(),doDelete() 等方法。
1、HttpServlet# service()
2、FrameworkServlet# doGet() 或 doPost() 或 doPut() 或 doDelete()
3、FrameworkServlet# processRequest()
1、HttpServlet#service()
HttpServletRequest 和 HttpServletResponse 对象是由 Servlet 容器(Tomcat)在调用 Servlet 的 service() 方法之前创建和初始化的。
最终所有的请求都会走到FrameworkServlet的processRequest()中
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
1.2 FrameworkServlet#doPost()
1.2 FrameworkServlet#doGet()
1.2 FrameworkServlet#doPut()
1.2 FrameworkServlet#doDelete()
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Delegate POST requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Delegate PUT requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Delegate DELETE requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
1.3 FrameworkServlet# processRequest()
在processRequest(request, response)方法中,主要执行了如下步骤:
【1】获得当前和最新request中的国际化上下文LocaleContext;
【2】获得当前和最新request中的请求参数RequestAttributes;
【3】初始化异步请求管理器WebAsyncManager;
【4】将最新request中的“国际化上下文”和“请求参数”设置到当前线程的上下文中,在整个doService共享,在finally后删除。
【5】doService()处理Http请求;
【6】将当前线程上下文中的“国际化上下文”和“请求参数”还原为之前的值;
【7】无论成功与否,都会发布ServletRequestHandledEvent事件;
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
// 针对【国际化上下文】,获得当前的LocaleContext和最新request请求中的LocaleContext
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
// 针对【请求参数】,获得当前的RequestAttributes和最新request请求中的RequestAttributes
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
// 初始化【异步请求管理器】
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
// 将request中最新的“国际化上下文”和“请求参数”设置到当前线程的上下文中
initContextHolders(request, localeContext, requestAttributes);
try {
/** 处理请求 */
doService(request, response);
}
catch (ServletException | IOException ex) {...}
catch (Throwable ex) {...}
finally {
// 还原以前的国际化上下文和请求参数设置到当前线程的上下文中
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) requestAttributes.requestCompleted();
// 无论成功与否,都会发布ServletRequestHandledEvent事件
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
2、doService(request, response)
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
Map<String, Object> attributesSnapshot = null;
/** 在include请求时保存请求属性的快照,以便在include请求后恢复原始属性 */
if (WebUtils.isIncludeRequest(request)) {
// 确定给定的请求是否是一个include请求(判断方法:request中是否存在“javax.servlet.include.request_uri”的属性参数)
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
// DEFAULT_STRATEGIES_PREFIX="org.springframework.web.servlet"
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX))
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
/** 设置request属性 */
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, 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); // request.setAttribute(PATH_ATTRIBUTE, requestPath);
}
/** 处理Http请求 */
try {
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (attributesSnapshot != null)
restoreAttributesAfterInclude(request, attributesSnapshot); // include请求后恢复原始属性
}
if (this.parseRequestPath)
ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request); // 还原请求参数中PATH_ATTRIBUTE的值
}
}
3、doDispatch(request, response)
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请求,则将request转换为MultipartHttpServletRequest类型 */
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
/**根据request,寻找匹配的Handler */
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response); // 如果没找到,则抛出异常或者返回404
return;
}
/**根据Handler,寻找匹配的HandlerAdapter */
HandlerAdapter ha = 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;
}
/**调用已注册的拦截器列表interceptors的preHandle方法 */
if (!mappedHandler.applyPreHandle(processedRequest, response)) return;
/**处理请求的逻辑并返回ModelAndView */
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) return;
//如果没有视图View,则向mv中设置默认的视图名称
applyDefaultViewName(processedRequest, mv);
//调用已注册的拦截器列表interceptors的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
// 省略代码
}
catch (Throwable err) {
//省略代码
}
/**调用handler以及处理返回的结果,该结果要么是ModelAndView,要么就是一个需要解析到ModelAndView的异常 */
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//省略代码
}
catch (Throwable err) {
//省略代码
}
finally {
//省略代码
}
}
3.1 getHandler(request)
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
/** 2.1.1 试图从request请求中获取handler实例 **/
Object handler = getHandlerInternal(request);
if (handler == null) handler = getDefaultHandler(); // 如果获取不到,则获取默认handler,
if (handler == null) return null; // 如果仍然获取不到,则直接返回null
// 如果上面获取到的header是字符串类型的beanName,则从IOC中获取到对应的bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 确保拦截器等的缓存查找路径(lookupPath)的存在
if (!ServletRequestPathUtils.hasCachedPath(request))
initLookupPath(request);
/** 2.1.2 将配置中对应的拦截器加入到执行链中,以确保拦截器生效 */
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// 针对CORS(跨域)请求,进行特殊处理
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = getCorsConfiguration(handler, request);
if (getCorsConfigurationSource() != null) {
CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
config = (globalConfig != null ? globalConfig.combine(config) : config);
}
if (config != null) {
config.validateAllowCredentials();
}
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
3.1.1 getHandlerInternal(request)
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
try {
return super.getHandlerInternal(request); // 调用AbstractHandlerMethodMapping的getHandlerInternal方法
}
finally {
ProducesRequestCondition.clearMediaTypesAttribute(request);
}
}
> AbstractHandlerMethodMapping#getHandlerInternal(request)
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
/**【步骤1】从request中寻找请求路径 */
String lookupPath = initLookupPath(request); // eg: lookupPath="/hello"
this.mappingRegistry.acquireReadLock();
try {
/**【步骤2】通过lookupPath和request,获得请求待流转的方法handlerMethod */
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
3.1.2、initLookupPath()
// eg: lookupPath="/hello"
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
/**【步骤1】根据请求路径lookupPath来获得可以匹配处理的方法列表 */
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
/**【步骤2】从directPathMatches获取匹配的Match实例对象,并保存到matches集合中 */
if (directPathMatches != null)
// 根据request对象,解析出http请求method、参数params,请求headers等信息来创建RequestMappingInfo对象,
// 然后封装到Match对象中,并保存到matches中
addMatchingMappings(directPathMatches, matches, request);
if (matches.isEmpty())
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
/**【步骤3】针对已匹配的Match集合对象进行处理 */
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
// 发现匹配上了两个相同的method,则进行特殊处理或者抛出异常
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (CorsUtils.isPreFlightRequest(request))
for (Match match : matches)
if (match.hasCorsConfig()) return PREFLIGHT_AMBIGUOUS_MATCH;
else {
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.getHandlerMethod().getMethod();
Method m2 = secondBestMatch.getHandlerMethod().getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
}
// eg: bestMatch.getHandlerMethod()=com.muse.springbootdemo.controller.DemoController#hello()
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
handleMatch(bestMatch.mapping, lookupPath, request); // 对request进行附加属性赋值
return bestMatch.getHandlerMethod(); // 返回com.muse.springbootdemo.controller.DemoController#hello()
}
/**【步骤4】没有找到已匹配的Match集合对象,则进行异常抛出等操作 */
else return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
> getMappingsByDirectPath()
// eg:urlPath="/hello"
public List<T> getMappingsByDirectPath(String urlPath) {
return this.pathLookup.get(urlPath); // eg:return {GET [/hello]}
}
3.1.3、getHandlerExecutionChain(handler, request)
【Object handler】真正处理请求的headler;
【List interceptorList】interceptor拦截器列表;
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//【步骤1】要么强转HandlerExecutionChain类型,要么新建HandlerExecutionChain实例对象
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
//【步骤2】遍历adaptedInterceptors,将符合条件的拦截器加入到chain中
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(request))
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
else chain.addInterceptor(interceptor);
}
return chain;
}
实现一个自定义的请求拦截器时,可以通过实现HandlerInterceptor接口的方式,这个接口一共有3个方法,分别是针对处理请求之前进行拦截操作的preHandle方法,以及针对处理请求之后进行拦截操作的postHandle方法,和在所有请求处理完毕之后进行额外操作afterCompletion方法,代码如下所示:
public interface HandlerInterceptor {
// 在处理请求之前进行额外操作
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
// 在处理请求之后进行额外操作
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {}
// 在所有请求处理完毕之后进行额外操作
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {}
}
3.2 getHandlerAdapter(request)
我们会通过逐一遍历根据handlerAdapters集合,通过调用HandlerAdapter的supports(handler)方法,来获取与入参handler相匹配的HandlerAdapter,只要找到了匹配的HandlerAdapter,直接返回即可,不再继续遍历对比.
handlerAdapters默认包含4个HandlerAdapter,分别是:
RequestMappingHandlerAdapter
HandlerFunctionAdapter
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null)
for (HandlerAdapter adapter : this.handlerAdapters)
if (adapter.supports(handler)) // 寻找到匹配的adapter
return adapter; // eg: RequestMappingHandlerAdapter@7511
// 如果没有找到HandlerAdapter,则抛出异常
throw new ServletException(...);
}
HandlerAdapter接口
public interface HandlerAdapter {
// 是否匹配该HandlerAdapter
boolean supports(Object handler);
// 处理请求,返回结果ModelAndView
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
// 用于请求缓存,已作废
@Deprecated
long getLastModified(HttpServletRequest request, Object handler);
}
3.3 handle()
public final ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
3.3.1 handleInternal()
在该方法中,主要是执行了两个步骤:
【步骤1】调用invokeHandlerMethod(request, response, handlerMethod)方法真正的执行请求处理;
【步骤2】对于Header不包含 “Cache-Control”的情况进行特殊处理。
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
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
3.3.1.1 invokeHandlerMethod()
【1】进行实例对象的创建及赋值操作,包含:webRequest、binderFactory、modelFactory、invocableMethod、……
【2】通过invocableMethod.invokeAndHandle(webRequest, mavContainer)方法,进行请求处理;
【3】通过getModelAndView(mavContainer, modelFactory, webRequest)方法,将执行结果封装为ModelAndView实例对象;
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
// 创建webRequest
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 创建binderFactory和modelFactory
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 创建及设置invocableMethod
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);
// 创建及设置mavContainer
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 创建及设置asyncWebRequest
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 创建及设置asyncManager
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();
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
/** 处理请求,实际执行逻辑的地方 */
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) return null;
// 处理请求返回结果,获得ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
1 invokeAndHandle()
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
/** 通过反射请求到具体的Controller上,并获得返回值 */
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 根据ResponseStatus注释设置响应状态
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);
/** 针对利用HandlerMethodReturnValueHandler的handleReturnValue方法,对返回值进行处理 */
try {
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {throw ex;}
}
/**
* 根据ResponseStatus注释设置响应状态
*/
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
// 获得请求响应状态,如果为null,则直接返回
HttpStatus status = getResponseStatus();
if (status == null) return;
// 获得请求响应response,尝试为response设置失败信息(response.sendError)或者状态码(response.setStatus)
HttpServletResponse response = webRequest.getResponse();
if (response != null) {
String reason = getResponseStatusReason();
if (StringUtils.hasText(reason)) response.sendError(status.value(), reason);
else response.setStatus(status.value());
}
// 被RedirectView获取
webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
}
>>>>>> invokeForRequest()
对request请求中的参数进行解析,转换为方法的入参args,然后再采用反射的方式调用Controller类的所对应的处理方法,获得最终处理后的结果:
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
/** 解析出请求的入参 **/
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
/** 利用反射,调用Controller类的所对应的处理方法 */
return doInvoke(args);
}
/**
* 请求参数解析
*/
protected Object[] getMethodArgumentValues(NativeWebRequest request,
ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获得http请求中的参数列表,如果没有入参,则直接返回空的入参数组
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) return EMPTY_ARGS;
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
// 如果参数属于providedArgs类型,则跳过,不进行解析
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) continue;
/** 如果所有resolver解析器都不能解析的话,则直接抛出异常 */
if (!this.resolvers.supportsParameter(parameter)) throw new IllegalStateException(...);
/** 进行参数解析操作 */
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception ex) {throw ex;}
}
return args;
}
/**
* 通过反射,执行逻辑调用
*/
protected Object doInvoke(Object... args) throws Exception {
// 获得被桥接的方法,即:用户自定义的方法
Method method = getBridgedMethod();
try {
if (KotlinDetector.isSuspendingFunction(method))
return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);
// 利用反射,调用Controller类中相应的method方法
return method.invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {...}
catch (InvocationTargetException ex) {...}
}
>>>>>>> supportsParameter(parameter)
该方法主要确定这个入参我们的解析器是否支持解析
public boolean supportsParameter(MethodParameter parameter) {
// 获取方法参数解析器
return getArgumentResolver(parameter) != null;
}
>>>>>>> resolveArgument()
在这个方法会依次遍历每个解析器的 supportsParameter(parameter) 方法来寻找可以解析入参parameter的具体解析器实现类resolver,如果找到了主要判断parameter参数是否有解析器可以对其进行解析;
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
//【步骤1】获取方法参数解析器
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null)
throw new IllegalArgumentException("Unsupported parameter type ...");
//【步骤2】执行解析操作
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
>>>>>>>> getArgumentResolver() 获取入参解析器
RequestParamMethodArgumentResolver:负责处理@RequestParam
RequestHeaderMethodArgumentResolver:负责处理@RequestHeader
SessionAttributeMethodArgumentResolver:负责处理@SessionAttribute
RequestAttributeMethodArgumentResolver:负责处理@RequestAttribute
RequestResponseBodyMethodProcessor:负责处理@RequestBody
…
/**
* 获得可以解析parameter参数的方法参数解析器(HandlerMethodArgumentResolver)
*/
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
// 如果之前解析过,则直接从缓存中获取
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) { // supportsParameter方法是由子类实现的
result = resolver;
this.argumentResolverCache.put(parameter, result); // 保存到缓存中
break;
}
}
}
return result;
}
>>>>>> handleReturnValue()
主要寻找可以对结果进行处理的handler实例对象;然后调用handler的handleReturnValue()方法来进行结果的处理。
HandlerMethodReturnValueHandler来处理返回值:
RequestResponseBodyMethodProcessor:处理加了@ResponseBody注解的情况
ViewNameMethodReturnValueHandler:处理没有加@ResponseBody注解并且返回值类型为String的情况
ModelMethodProcessor:处理返回值是Model类型的情况
…等等其他得默认的一些处理器
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
/** 选择可以对结果进行解析的解析器 */
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) throw new IllegalArgumentException("Unknown return value type: " + ...);
/** 具体解析操作,由子类负责 */
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
/**
* 选择可以对结果进行解析的解析器
*/
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler))
continue;
if (handler.supportsReturnType(returnType)) // 由子类负责实现supportsReturnType方法
return handler;
}
return null;
}
>>>>>>>>>>RequestResponseBodyMethodProcessor#handleReturnValue()
RequestResponseBodyMethodProcessor会处理加了@ResponseBody注解的情况,也是常用的一种。会直接方法返回的结果直接响应给浏览器,返回的结果可能是字符串 ;可能是对象; 可能是Map或者其他形式的。
@ResponseBody
public String test() {
return "张三";
}
>------------------>默认的4个MessageConverter
SpringMVC会利用HttpMessageConverter来处理;
- ByteArrayHttpMessageConverter:处理返回值为字节数组的情况,把字节数组返回给浏览器
- StringHttpMessageConverter:处理返回值为字符串的情况,把字符串按指定的编码序列号后返回给浏览器
protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
HttpHeaders headers = outputMessage.getHeaders();
if (this.writeAcceptCharset && headers.get(HttpHeaders.ACCEPT_CHARSET) == null) {
headers.setAcceptCharset(getAcceptedCharsets());
}
Charset charset = getContentTypeCharset(headers.getContentType());
StreamUtils.copy(str, charset, outputMessage.getBody());
}
- SourceHttpMessageConverter:处理返回值为XML对象的情况,比如把DOMSource对象返回给浏览器
- AllEncompassingFormHttpMessageConverter:处理返回值为MultiValueMap对象的情况
>------------------>特殊的MappingJackson2HttpMessageConverter
MappingJackson2HttpMessageConverter,这个Converter比较强大,能把String、Map、User对象等等都能转化成JSON格式。
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
messageConverter.setDefaultCharset(StandardCharsets.UTF_8);
converters.add(messageConverter);
}
}
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
3.4 processDispatchResult()
private void processDispatchResult(HttpServletRequest request,
HttpServletResponse response,
HandlerExecutionChain mappedHandler,
ModelAndView mv,
Exception exception) throws Exception {
boolean errorView = false;
//【步骤1】如果出现了异常,则进行异常处理
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException)
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
//【步骤2】如果存在mv,则对mv进行渲染操作
if (mv != null && !mv.wasCleared()) {
render(mv, request, response); /** 执行页面渲染操作 */
if (errorView) WebUtils.clearErrorRequestAttributes(request);
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) return;
if (mappedHandler != null)
mappedHandler.triggerAfterCompletion(request, response, null);
}
3.4.1 processHandlerException(request, response, handler, exception)
具体流程见异常处理描述
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
// Success and error responses may use different content types
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
if (exMv != null) {
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
// We might still need view name translation for a plain error model...
if (!exMv.hasView()) {
String defaultViewName = getDefaultViewName(request);
if (defaultViewName != null) {
exMv.setViewName(defaultViewName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using resolved error view: " + exMv, ex);
}
else if (logger.isDebugEnabled()) {
logger.debug("Using resolved error view: " + exMv);
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
throw ex;
}
@Override
@Nullable
public ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
if (shouldApplyTo(request, handler)) {
prepareResponse(ex, response);
ModelAndView result = doResolveException(request, response, handler, ex);
if (result != null) {
// Print debug message when warn logger is not enabled.
if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {
logger.debug("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));
}
// Explicitly configured warn logger in logException method.
logException(ex, request);
}
return result;
}
else {
return null;
}
}
3.4.2 render(mv, request, response)
尝试获得View实例对象;然后对view对象页面渲染
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isTraceEnabled()) {
logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
3.4.2.1 resolveViewName()
通过resolveViewName()来创建view视图对象,并将其加入到IOC中,其具体实现方式还是遍历每一个视图解析器(ViewResolver),调用其resolverViewName(viewName, locale)方法,尝试获得View视图实例对象,如果获得到了,则直接返回,不需要继续遍历其他的视图解析器了
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
@Override
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
if (!isCache()) {
return createView(viewName, locale);
}
else {
Object cacheKey = getCacheKey(viewName, locale);
View view = this.viewAccessCache.get(cacheKey);
if (view == null) {
synchronized (this.viewCreationCache) {
view = this.viewCreationCache.get(cacheKey);
if (view == null) {
// Ask the subclass to create the View object.
view = createView(viewName, locale);
if (view == null && this.cacheUnresolved) {
view = UNRESOLVED_VIEW;
}
if (view != null) {
this.viewAccessCache.put(cacheKey, view);
this.viewCreationCache.put(cacheKey, view);
}
}
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace(formatKey(cacheKey) + "served from cache");
}
}
return (view != UNRESOLVED_VIEW ? view : null);
}
}
createView()
最终创建视图是通过loadView()
@Nullable
protected View createView(String viewName, Locale locale) throws Exception {
return loadView(viewName, locale);
}
@Override
protected View loadView(String viewName, Locale locale) throws Exception {
AbstractUrlBasedView view = buildView(viewName);
View result = applyLifecycleMethods(viewName, view);
return (view.checkResource(locale) ? result : null);
}
loadView()->buildView(viewName)
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
Class<?> viewClass = getViewClass();
Assert.state(viewClass != null, "No view class");
AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);
view.setUrl(getPrefix() + viewName + getSuffix());
String contentType = getContentType();
if (contentType != null) {
view.setContentType(contentType);
}
view.setRequestContextAttribute(getRequestContextAttribute());
view.setAttributesMap(getAttributesMap());
Boolean exposePathVariables = getExposePathVariables();
if (exposePathVariables != null) {
view.setExposePathVariables(exposePathVariables);
}
Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
if (exposeContextBeansAsAttributes != null) {
view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
}
String[] exposedContextBeanNames = getExposedContextBeanNames();
if (exposedContextBeanNames != null) {
view.setExposedContextBeanNames(exposedContextBeanNames);
}
return view;
}
loadView()->applyLifecycleMethods(viewName, view)
initializeBean() ioc的知识了
protected View applyLifecycleMethods(String viewName, AbstractUrlBasedView view) {
ApplicationContext context = getApplicationContext();
if (context != null) {
Object initialized = context.getAutowireCapableBeanFactory().initializeBean(view, viewName);
if (initialized instanceof View) {
return (View) initialized;
}
}
return view;
}
3.4.2.2 view.render(mv.getModelInternal(), request, response)
@Override
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("View " + formatViewName() +
", model " + (model != null ? model : Collections.emptyMap()) +
(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
}
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
/** 渲染前的准备操作(可由子类自定义实现)*/
prepareResponse(request, response);
/** 将渲染后的视图合并到输出流中(可由子类自定义实现)*/
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
1 prepareResponse()
/**
* 试图View被渲染前的准备操作
*/
protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {
setResponseContentType(request, response); // 设置response响应的ContentType
response.setCharacterEncoding(this.encoding.getJavaName()); // 设置response响应的CharacterEncoding
if (this.disableCaching) response.addHeader("Cache-Control", "no-store"); // 设置response响应的Cache-Control
}
2 renderMergedOutputModel()
/**
* 将渲染后的视图合并到输出流中
*/
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
ByteArrayOutputStream temporaryStream = null;
OutputStream stream;
//【步骤1】获得相应的输出流
if (this.updateContentLength) {
temporaryStream = createTemporaryOutputStream();
stream = temporaryStream;
}
else stream = response.getOutputStream();
//【步骤2】试图serializationView和filters包装在MappingJacksonValue实例对象中
Object value = filterAndWrapModel(model, request);
//【步骤3】将渲染的视图value保存到输出流stream中
writeContent(stream, value);
if (temporaryStream != null)
writeToResponse(response, temporaryStream);
}