Servlet is an API that provides many interfaces and classes including documentation.
Servlet is an interface that must be implemented for creating any Servlet.
Servlet is a class that extends the capabilities of the servers and responds to the incoming requests. It can respond to any requests.
其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类。
最原始的Servlet接口有三个主要方法:init、service和destroy;
/**
* Defines methods that all servlets must implement.
*
* @author Various
*
* @see GenericServlet
* @see javax.servlet.http.HttpServlet
*
*/
public interface Servlet {
/**
* Called by the servlet container to indicate to a servlet that the
* servlet is being placed into service.
*/
public void init(ServletConfig config) throws ServletException;
/**
* Returns a {@link ServletConfig} object, which contains
* initialization and startup parameters for this servlet.
*/
public ServletConfig getServletConfig();
/**
* Called by the servlet container to allow the servlet to respond to
* a request.
*/
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
/**
* Returns information about the servlet, such
* as author, version, and copyright.
*/
public String getServletInfo();
/**
* Called by the servlet container to indicate to a servlet that the
* servlet is being taken out of service.
*/
public void destroy();
}
GenericServlet defines a generic, protocol-independent servlet.
GenericServlet抽象类包含以下主要方法,可以看出主要还是围绕着init、service和destroy;
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable {
/**
* Called by the servlet container to indicate to a servlet that the
* servlet is being taken out of service. See {@link Servlet#destroy}.
*/
public void destroy() { }
/**
* Called by the servlet container to indicate to a servlet that the
* servlet is being placed into service. See {@link Servlet#init}.
*/
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
/**
* A convenience method which can be overridden so that there's no need
* to call super.init(config)
.
*/
public void init() throws ServletException { }
/**
* Called by the servlet container to allow the servlet to respond to
* a request. See {@link Servlet#service}.
*/
public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
/**
* Returns the name of this servlet instance.
*/
public String getServletName() {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getServletName();
}
}
HttpServlet provides an abstract class to be subclassed to create an HTTP servlet suitable for a Web site.
HttpServlet的主要内容如下,主要是提供了service方法,使得继承该类的方法无需再override。定义了doGet、doPost等一系列方法,但并未给出具体实现。
public abstract class HttpServlet extends GenericServlet implements java.io.Serializable {
/**
* Called by the server (via the service
method) to
* allow a servlet to handle a GET request.
*/
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
NoBodyResponse response = new NoBodyResponse(resp);
doGet(req, response);
response.setContentLength();
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
/**
*
* Receives standard HTTP requests from the public
* service
method and dispatches
* them to the do
XXX methods defined in
* this class. This method is an HTTP-specific version of the
* {@link javax.servlet.Servlet#service} method. There's no
* need to override this method.
*/
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 / 1000 * 1000)) {
// 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);
}
}
/**
* Dispatches client requests to the protected
* service
method. There's no need to
* override this method.
*/
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
}
Servlet如果需要给客户端返回数据,比如一个HTML文件,需要一行一行的把HTML语句给用Writer输出,早期简单的网页还能应付得住,但是随着互联网的不断发展,网站的内容和功能越来越强大,一个普通的HTML文件可能就达到好几百行,如果在采用使用Servlet去一行一行的输出HTML代码的话,将会非常的繁琐并且浪费大量的时间,且在当时,出现了PHP这种可以内嵌到HTML文件的动态语言,使得制作动态网页变得异常的简单和轻松,因此大量的程序员转上了PHP语言的道路,JAVA的份额急剧减小,当时JAVA的开发者Sun公司为了解决这个问题,也开发出了自己的动态网页生成技术,使得同样可以在HTML文件里内嵌JAVA代码,这就是现在的JSP技术。
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。MVC主要作用是降低了视图与业务逻辑间的双向耦合。
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。 也就是说控制器做了个调度员的工作。
流程:
MVC不是一种设计模式,而是一种架构模式。
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。
Spring MVC的特点:
Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。
FrameworkServlet is the base servlet for Spring’s web framework. Provides integration with a Spring application context, in a JavaBean-based overall solution.
HttpServlrtBean抽象类:Simple extension of HttpServlet which treats its config parameters (init-param entries within the servlet tag in web.xml) as bean properties.
看一下FrameworkServlet抽象类的主要方法,发现把doXXX方法都统一到doService抽象方法上了;
/**
* Override the parent class implementation in order to intercept PATCH requests.
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
/**
* Delegate GET requests to processRequest/doService.
*/
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Delegate POST requests to {@link #processRequest}.
*/
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Process this request, publishing an event regardless of the outcome.
* The actual event handling is performed by the abstract
* {@link #doService} template method.
*/
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
/**
* Subclasses must implement this method to do the work of request handling,
* receiving a centralized callback for GET, POST, PUT and DELETE.
*/
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception;
Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers or HTTP-based remote service exporters. Dispatches to registered handlers for processing a web request, providing convenient mapping and exception handling facilities.
DispatcherServlet类override了FrameworkServlet的doService方法,并将最终的处理流程放在了doDispatch方法里,该方法很值得研究,写了一些注释,接下来会详细分析带有标号的注释对应的代码。
/**
* Process the actual dispatching to the handler.
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
//获取异步处理管理器,servlet3.0后支持异步处理,可以在子线程中响应用户请求
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 解析multipart类型的请求,上传文件用的就是multipart类型的请求方式
processedRequest = checkMultipart(request);
// 用来标记是否是multipart类型的请求
multipartRequestParsed = (processedRequest != request);
// 1. 获取HandlerExecutionChain对象
mappedHandler = getHandler(processedRequest);
// 如果没有获取到,就抛异常
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2. 根据Handler获取HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 调用拦截器的preHandle方法,若返回false,处理结束
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 4. 通过HandlerAdapter调用Handler实际处理请求,获取ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 判断异步请求不是已经开始了,开始了就返回了
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 如果mv对象中没有视图且DispatcherServlet配置了默认的视图,则给mv安排一个默认的视图
applyDefaultViewName(processedRequest, mv);
// 5. 调用拦截器的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 6. 处理分发结果,渲染视图(包含了正常处理和异常情况的处理),将结果输出到客户端
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 7. 调用拦截器的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
// 7. 调用拦截器的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
// 对于异步处理的情况,调用异步处理的拦截器AsyncHandlerInterceptor的afterConcurrentHandlingStarted方法
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
//对于multipart的请求,清理资源,比如文件上传的请求,上传的过程中文件会被保存到临时文件中,这里就会对这些文件继续清理
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
// 1. 获取HandlerExecutionChain对象
mappedHandler = getHandler(processedRequest);
来看一下getHandler方法:
/**
* Return the HandlerExecutionChain for this request.
*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
遍历了handlerMappings,分别调用它们的getHandler方法,找到对应的HandlerExecutionChain;
HandlerExecutionChain类中主要包含以下三个属性:
// 请求处理器,通常就是我们自定义的 controller 对象及方法
private final Object handler;
// 当前请求匹配到的拦截器列表
private List<HandlerInterceptor> interceptorList;
// 拦截器索引,用来记录执行到第几个拦截器了
private int interceptorIndex;
在AbstractHandlerMapping抽象类中,getHandler方法首先调用了getHandlerInternal方法,通过寻找、读取配置文件,找到request对应的handler,然后调用了getHandlerExecutionChain方法,通过路径匹配,找到对应的interceptors;
// 2. 根据Handler获取HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
来看一下getHandlerAdapter方法:
/**
* Return the HandlerAdapter for this handler object.
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
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");
}
遍历handlerAdapters,找到能够处理当前 Handler 的HandlerAdapter,如果没找到会报错;
// 3. 调用拦截器的preHandle方法,若返回false,处理结束
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
来看下applyPreHandle方法:
/**
* Apply preHandle methods of registered interceptors.
*/
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];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
该方法首先循环调用拦截器的preHandle方法,如果某个拦截器的preHandle方法返回 false,则调用triggerAfterCompletion方法,且记录了拦截器的执行位置;
来看下triggerAfterCompletion方法:
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
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);
}
}
}
}
该方法反向依次调用那些 preHandle 方法返回 ture 的拦截器的 afterCompletion 方法;
// 4. 通过HandlerAdapter调用Handler实际处理请求,获取ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
来看下handle方法,handle方法会走到org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod:
/**
* Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
* if view resolution is required.
*/
@Nullable
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();
}
}
上述方法主要做了三件事:
组装目标方法需要的参数;
org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues
在该方法中,使用HandlerMethodArgumentResolver进行解析请求,得到参数;
HandlerMethodArgumentResolver有很多实现类,归纳如下:
实现类 | 对应的控制器参数 | 说明 |
---|---|---|
PathVariableMapMethodArgumentResolver | @PathVariable 标注参数 | 从 url 中提取参数的值 |
RequestHeaderMethodArgumentResolver | @RequestHeader 标注参数 | 从 http 头中提取参数值 |
RequestParamMethodArgumentResolver | @RequestParam 标注参数 | 从http 请求参数中获取值 |
RequestResponseBodyMethodProcessor | @RequestBody 标注参数 | 提取 body 数据,转换为参数类型 |
ServletResponseMethodArgumentResolver | ServletResponse、OutputStream、Writer 这 3 种类型的参数 | 这几种类型用来控制 http 请求的响应输出流 |
HttpEntityMethodProcessorHttpEntity | HttpEntity 类型的参数 | HttpEntity 中包含了 http 请求头和 body 的所有信息 |
ExpressionValueMethodArgumentResolver | @Value 标注的参数 | spel 表达式,从 spring 容器中获取值 |
MapMethodProcessor | 参数为 Map 或者子类型 | - |
ModelMethodProcessor | 参数为 org.springframework.ui.Model 或子类型 | - |
ModelAttributeMethodProcessor | @ModelAttribute 标注的参数 | - |
通过反射调用处理请求的目标方法,获取方法的返回值;
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
对方法的返回值进行处理;
org.springframework.web.method.support.HandlerMethodReturnValueHandler
该接口有两个方法:
/**
* Whether the given {@linkplain MethodParameter method return type} is
* supported by this handler
*/
boolean supportsReturnType(MethodParameter returnType);
/**
* Handle the given return value by adding attributes to the model and
* setting a view or setting the
* {@link ModelAndViewContainer#setRequestHandled} flag to {@code true}
* to indicate the response has been handled directly.
*/
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
归纳如下:
实现类 | 说明 |
---|---|
ViewNameMethodReturnValueHandler | 返回值为视图名称时的解析器 |
MapMethodProcessor | 返回值为 Map 的解析器 |
StreamingResponseBodyReturnValueHandler | 返回值为 ResponseEntity 类型时的解析器 |
DeferredResultMethodReturnValueHandler | 返回值为 DeferredResult 类型时的解析器,表示异步请求 |
CallableMethodReturnValueHandler | 返回值为 Callable 类型时的解析器,表示异步请求 |
ModelMethodProcessor | 返回值为 Model 类型时的解析器 |
ModelAndViewMethodReturnValueHandler | 返回值为 ModelAndView 类型时的解析器 |
RequestResponseBodyMethodProcessor | 方法上标注有@ResponseBody 注解时返回值的解析器 |
HttpEntityMethodProcessor | 返回值为 HttpEntity 类型但是非 RequestEntity 类型时的解析器 |
以其中的RequestResponseBodyMethodProcessor为例,来看下源码:
@Override
public boolean supportsReturnType(MethodParameter returnType) {
// 判断类上或者目标方法上是否有@ResponseBody注解
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
// 1:标注为请求已处理,因为当前handleReturnValue方法会直接将结果输出到客户端,所以后续就不需要再进行视图渲染了,表示请求已经被处理了
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// 2:将结果输出到客户端
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
注意,并不是所有的实现类的handleReturnValue方法都将结果直接返回给客户端了,有些是需要渲染的;
// 5. 调用拦截器的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
来看下applyPostHandle方法:
/**
* Apply postHandle methods of registered interceptors.
*/
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];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
逆序调用拦截器的postHandle方法;
// 6. 处理分发结果,渲染视图(包含了正常处理和异常情况的处理),将结果输出到客户端
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
/**
* Handle the result of handler selection and handler invocation, which is
* either a ModelAndView or an Exception to be resolved to a ModelAndView.
*/
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
mv = processHandlerException(request, response, handler, exception);
看一下processHandlerException方法:
/**
* Determine an error ModelAndView via the registered HandlerExceptionResolvers.
*/
@Nullable
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
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) {
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
throw ex;
}
该方法主要是遍历HandlerExceptionResolver的resolveException方法来处理异常;
render(mv, request, response);
看一下render方法:
/**
* Render the given ModelAndView.
*/
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
}
view.render(mv.getModelInternal(), request, response);
}
该方法主要做了两件事:
调用resolveViewName方法解析视图名称得到 View;
调用render方法渲染视图;
看一下render方法,发现最终走到org.springframework.web.servlet.view.AbstractView#renderMergedOutputModel方法中,以其实现类override的方法org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel为例:
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 将model中的数据遍历后放在request中(request.setAttribute(name,value))
exposeModelAsRequestAttributes(model, request);
// 获取跳转的页面的路径
String dispatcherPath = prepareForRendering(request, response);
// 调用getRequestDispatcher得到RequestDispatcher对象
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
//实现页面跳转
if (useInclude(request, response)) {
rd.include(request, response);
}else {
rd.forward(request, response);
}
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
来看一下这部分源码:
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
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);
}
}
}
}
主要是反向调用拦截器的afterCompletion方法;