Servlet
Servlet的生命周期
Servlet 的生命周期可以分为四个步骤:
-
实例化。当 Web 容器(如Tomcat)启动时,会首先加载 Servlet 类,并创建 Servlet 实例。这一过程通常在应用程序启动时完成。
-
初始化。接着容器会调用 Servlet 实例的 init() 方法来进行初始化操作。在这个方法中,通常会加载并初始化与 Servlet 相关的资源,如数据库连接池、配置文件等。
-
加载和处理请求。当客户端发出请求时,容器会创建一个新的线程来处理该请求,在该线程中调用 Servlet 的 service() 方法,并将请求传递给它。根据不同的 HTTP 请求类型,Servlet 会调用 doGet()、doPost() 等方法来处理请求,并生成相应的响应数据。
-
销毁。在 Servlet 生命周期结束时,容器会调用 destroy() 方法来销毁 Servlet 实例,释放相关的资源。
注:在应用启动的时候,web容器就会实例化初始化Servlet。但是考虑到不必要的资源消耗,提高应用程序的性能和响应速度,采用了懒加载的方式,只有在第一次请求到达后,才会实例化初始化Servlet
Servlet接口
- Servlet对象主要封装了对HTTP请求的处理, 他的运行 需要Servlet容器(Tomcat,Jetty)的支持。
- Servlet由Servlet容器进行管理,Servlet容器将Servlet动态加载到服务器上,与HTTP协议相关的Servlet使用HTTP请求和HTTP响应与客户端进行交互。
- 如下图,Servlet的请求首先会被HTTP服务器(如Apache)接收,HTTP服务器只负责静态HTML界面的解析,而Servlet的请求则转交给Servlet容器,Servlet容器会根据请求路径以及Servlet之间的映射关系,调用相应的Servlet,Servlet将处理的结果返回给Servlet容器,并通过HTTP服务器将响应传输给客户端。
servlet容器
Servlet 容器指的是 Web 服务器或应用服务器,如 Tomcat、Jetty、Undertow 等,它们负责管理 Servlet 的生命周期、请求处理和响应生成等工作。
在 Servlet/JSP 规范中,Servlet 容器是作为 Web 容器的一部分来定义的。Web 容器是指能够解析和执行 Web 应用程序的软件环境,包括 Servlet 容器、JSP 引擎、Web 服务器、Java EE 应用服务器等。
Servlet 容器提供了一个运行时环境,能够加载并执行 Servlet,并提供许多 Servlet API 所需的服务,如会话管理、Cookie 处理、HTTP 请求和响应、重定向、安全认证等。Servlet 容器还提供了一些额外的服务,如 JNDI、JDBC 连接池、日志记录、缓存等。
常见的 Servlet 容器有 Tomcat、Jetty、Undertow 等。Tomcat 是 Apache 基金会下的一个 Java Servlet 容器,也是目前使用最为广泛的 Servlet 容器之一。Jetty 和 Undertow 也是常见的 Servlet 容器,它们具有更轻量级、更快速和更灵活的特点。
Servlet
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
MVC请求需要的大概接口:
Servlet的初始化
Servlet的init方法
当第一次请求到达后,servlet容器会调用init方法
GenericServlet implements Servlet
public void init(ServletConfig config) throws ServletException {
// 保存servlet配置 供后续使用
this.config = config;
// 调用init空方法,由子类实现
this.init();
}
public void init() throws ServletException {
}
HttpServlet extends GenericServlet
HttpServlet没有实现init方法
HttpServletBean extends HttpServlet
HttpServletBean 实现了init方法
HttpServletBean是一个class直接实现了HttpServlet,这个类主要负责配置文件(web.xml)里springmvc区域的属性操作
@Override
public final void init() throws ServletException {
// 通过init参数设置bean的属性
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// 空方法 让子类实现
initServletBean();
}
FrameworkServlet的初始化
FrameworkServlet extends HttpServletBean
重点:重写了initServletBean方法
@Override
protected final void initServletBean() throws ServletException {
// ......日志记录
try {
// 初始化应用程序上下文
this.webApplicationContext = initWebApplicationContext();
// 空方法 spring 没有实现 可自定义子类扩展
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
// ......日志记录
}
webApplicationContext
Web应用程序上下文是Spring提供的一个特殊的应用程序上下文,它会自动加载Web应用程序中的所有配置文件,并将所有的bean装配到容器中。
在这个过程中,Spring框架会扫描classpath路径下的所有类文件,找到包含@Controller、@Service、@Repository等注解的类,并将这些类注册为bean。
initWebApplicationContext方法详解:
protected WebApplicationContext initWebApplicationContext() {
// <1> 获得根 WebApplicationContext 对象
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
// <2> 获得 WebApplicationContext wac 变量
WebApplicationContext wac = null;
// 第一种情况,如果构造方法已经传入 webApplicationContext 属性,则直接使用
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
// 如果是 ConfigurableWebApplicationContext 类型,并且未激活,则进行初始化
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// 未激活
// 设置 wac 的父 context 为 rootContext 对象
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
// 配置和初始化 wac
configureAndRefreshWebApplicationContext(cwac);
}
}
}
// 第二种情况,从 ServletContext 获取对应的 WebApplicationContext 对象
if (wac == null) {
wac = findWebApplicationContext();
}
// 第三种,创建一个 WebApplicationContext 对象
if (wac == null) {
wac = createWebApplicationContext(rootContext);
}
// <3> 如果未触发刷新事件,则主动触发刷新事件
if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
onRefresh(wac);
}
}
// <4> 将 context 设置到 ServletContext 中
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
<1> WebApplicationContextUtils.getWebApplicationContext(getServletContext());
获取Root WebApplicationContext 对象
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
}
@Nullable
public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
Assert.notNull(sc, "ServletContext must not be null");
Object attr = sc.getAttribute(attrName);
if (attr == null) {
return null;
}
if (attr instanceof RuntimeException) {
throw (RuntimeException) attr;
}
if (attr instanceof Error) {
throw (Error) attr;
}
if (attr instanceof Exception) {
throw new IllegalStateException((Exception) attr);
}
if (!(attr instanceof WebApplicationContext)) {
throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr); }
return (WebApplicationContext) attr;
}
而这个是在Root WebApplicationContext 容器初始化的时候进行设置的:
org.springframework.web.context.ContextLoader#initWebApplicationContext
<2> 获得 WebApplicationContext wac 变量。下面,会分成三种情况。
1. 第一种情况:如果构造方法已经注入了webApplicationContext 属性,则直接使用
configureAndRefreshWebApplicationContext();
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// 如果 wac 使用了默认编号,则重新设置 id 属性。
if (this.contextId != null) {
wac.setId(this.contextId);
}
else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
}
}
// 设置 wac 的 servletContext、servletConfig、namespace 属性。
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
// 添加监听器 SourceFilteringListener 到 wac 中.
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// 初始化属性资源。
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
// 执行处理完 WebApplicationContext 后的逻辑。目前是个空方法,暂无任何实现。
postProcessWebApplicationContext(wac);
// 执行自定义初始化 context 。
applyInitializers(wac);
// 刷新 wac ,从而初始化 wac 。
wac.refresh();
}
WebApplicationContext 子父区别
Root WebApplicationContext 和普通的 WebApplicationContext 都是 Spring Web 应用上下文。
其中,Root WebApplicationContext 是整个应用的根上下文,典型的 Web 应用只有一个根上下文,它负责加载应用中的共享 Bean,例如数据源、事务管理器、业务服务等等。而普通的 WebApplicationContext 则是针对具体的 servlet 或 Filter 而言的,它们都属于 Root WebApplicationContext 的子上下文,负责加载特定于 servlet 或 Filter 的 Bean 定义及其他资源文件。
从上下文层面来看,对于普通的 WebApplicationContext 来说,它是依赖于 Root WebApplicationContext 的,它的父级就是 Root WebApplicationContext,而 Root WebApplicationContext 没有父级上下文。因此,对于普通的 WebApplicationContext 所加载的所有 Bean,都可以通过父级上下文 Root WebApplicationContext 获取到。
总之,Root WebApplicationContext 和普通的 WebApplicationContext 对于 Spring Web 应用的配置和管理非常重要,它们可以统一管理应用中的 Bean,并提供依赖注入、AOP 等常用功能,让我们可以更加便捷地开发 Web 应用程序。
2. 第二种情况:如果此处 wac 还是为空
findWebApplicationContext();
protected WebApplicationContext findWebApplicationContext() {
// 需要配置ContextAttribute属性,才会去查找
String attrName = getContextAttribute();
if (attrName == null) {
return null;
}
// 从servletContext中,获得属性名对应的WebApplicationContext对象
WebApplicationContext wac =
WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
}
return wac;
}
3. 第三种情况:如果此处 wac 还是为空,创建一个 WebApplicationContext 对象。
createWebApplicationContext(rootContext);
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
Class<?> contextClass = getContextClass();
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
// 创建 context 类的对象。
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
// 设置 environment、parent、configLocation 属性。其中,configLocation 是个重要属性。
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
// 配置和初始化 wac 跟方法一中调用的同一个方法 。
configureAndRefreshWebApplicationContext(wac);
return wac;
}
<3> 触发刷新机制执行onRefresh。 当 Servlet WebApplicationContext 刷新完成后,触发 Spring MVC 组件的初始化。
protected void onRefresh(ApplicationContext context) {
// For subclasses: do nothing by default.
}
这是一个空方法,具体在子类DispatcherServlet实现了。
DispatcherServlet extends FrameworkServlet
用于HTTP请求处理程序/控制器的中央调度器
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
// 文件解析器
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
// 初始化处理器映射器
initHandlerMappings(context);
// 初始化处理器适配器
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
// 视图解析器
initViewResolvers(context);
initFlashMapManager(context);
}
// initHandlerAdapters,initHandlerMappings这两个初始化的产生的对象将在后续处理请求时使用到
<4> 如果 publishContext 为 true 时,则将 context 设置到 ServletContext 中。
Servlet的请求处理
Servlet的service方法
Servlet 接口中的 service() 方法是用来处理客户端请求的核心方法
void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
GenericServlet implements Servlet
抽象方法,未实现
HttpServlet extends GenericServlet
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
if (!(req instanceof HttpServletRequest &&
res instanceof HttpServletResponse)) {
throw new ServletException("non-HTTP request or response");
}
// 包装Servlet请求响应对象
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
// 调用重载方法
service(request, response);
}
......
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
// 根据请求的方法类型 执行不同的doXxx()方法。在子类重写这些方法,我们就能完成自己的业务需求。
if (method.equals(METHOD_GET)) {
doGet(req, resp);
} else if (method.equals(METHOD_HEAD)) {
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 {
// ......异常处理
}
}
FrameworkServlet的service方法
HttpServletBean extends HttpServlet
HttpServletBean 没有对service()、 doXxx()方法做处理
FrameworkServlet extends HttpServletBean
FrameworkServlet中对service()、 doXxx()方法进行了重写
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
// PATCH方法单独调用processRequest
// 因为在父类中没有对该类型做处理 会走异常处理 所以在这里单独处理
processRequest(request, response);
}
else {
// 大部分情况调用父类的service方法
super.service(request, response);
}
}
PATCH 方法
在 HTTP/1.1 标准中,PATCH 方法用于对资源进行局部更新。与 PUT 方法不同,PUT 方法用于完全替换某个 URL 所代表的资源,而 PATCH 方法则是通过对已有资源的修改来更新该资源,只更新所需修改的部分。
由于 PATCH 方法比较特殊,与其他 HTTP 方法的处理方式略有不同,所以在这段代码中单独对 PATCH 方法进行了处理。具体来说,如果请求方法不是 PATCH 或者请求方法为 null,就调用父类的 service 方法进行处理;否则,就调用 processRequest 方法进行处理。
这样做的目的是因为 PATCH 方法相对于其他 HTTP 方法较为特殊,处理方式也比较复杂,需要进行特殊的处理。例如,在 RESTful API 设计中,PATCH 方法通常用于对一个资源进行局部更新,而且操作的粒度非常细,需要自己手动实现修改的逻辑。因此,这段代码中将 PATCH 方法单独处理,可以更加灵活地实现相关业务逻辑。
由于父类的doXxx()都被子类实现了,所以走的子类的实现。
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
// ......所有的doXxx()方法,都会执行processRequest(request, response);
processRequest(request, response);
处理此请求,无论结果如何都发布一个事件。 实际的事件处理是由抽象的doService模板方法执行的
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
// 申明一个异常顶层对象Throwable
Throwable failureCause = null;
// 本地化、国际化处理。
// 获取上一个LocaleContext,这里叫上一个,是因为此方法是从ThreadLocal中获取的,获取当前线程的LocaleContext。
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
// 构建一个本地国际化上下文,SimpleLocaleContext
LocaleContext localeContext = buildLocaleContext(request);
// 获取当前绑定到线程的RequestAttributes
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
// 构建ServletRequestAttributes
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
// 将localeContext和requestAttributes放入当前线程中
initContextHolders(request, localeContext, requestAttributes);
try {
// ***DispatcherServlet进行实现的。***
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);
}
}
DispatcherServlet extends FrameworkServlet
中央调度器中
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
// 保留请求属性的快照,以防出现include,
// 能够在include之后恢复原始属性。
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 向请求request中绑定 webApplication、localeResolver、themeResolver等组件
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());
// 看flashMap是否为null,不为空的话做如下操作。FlashMap是用于转发保存数据用的。
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
RequestPath previousRequestPath = null;
if (this.parseRequestPath) {
previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
ServletRequestPathUtils.parseAndCache(request);
}
try {
// ***分发处理请求***
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);
}
}
if (this.parseRequestPath) {
ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
}
}
}
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 {
// 检查当前请求是不是一个MultipartHttpServletRequest请求,(文件上传请求)
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 1. 获取处理器执行链(能处理请求的处理器和拦截器集合)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2. 通过处理器获取处理器适配器
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;
}
}
// 3. 前置拦截器执行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// ***4. 反射调用方式执行控制层代码***
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 5. 后置拦截器执行
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 6. 处理调度结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
1、getHandler(processedRequest);
// 返回此请求的HandlerExecutionChain。 按顺序尝试所有处理程序映射,获取(能处理请求的处理器和拦截器集合)
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 此处的所有处理器映射器都是在init初始化的时候创建的。
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
// 没有匹配上的 会返回null
if (handler != null) {
// 优先级高的handlerMappering能处理直接返回
return handler;
}
}
}
return null;
}
SpringMVC六个处理器映射器的作用
Spring MVC 中的处理器映射器(HandlerMapping)是用来将 HTTP 请求映射到具体的处理器(Handler)对象上的组件,它负责根据请求信息来确定如何处理该请求。
Spring MVC 框架提供了多个不同类型的 HandlerMapping 实现,每种实现方式都有其特定的应用场景。以下是 Spring MVC 中常见的 6 种 HandlerMapping 实现及其作用:
1. BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping 将请求的 URL 映射到对应的 Bean 名称上。例如,我们可以在 Spring 配置文件中声明一个名为 "/hello" 的 Bean,并将它映射到 "/hello.html" 请求上,则当客户端请求 "/hello.html" 时,就会将该请求映射到名为 "/hello" 的 Bean 上进行处理。
2. ControllerClassNameHandlerMapping
ControllerClassNameHandlerMapping 将请求的 URL 映射到对应的 Controller 类名上。例如,我们可以在 Spring 配置文件中声明一个名为 "UserController" 的 Controller 并将它映射到 "/user/*" 请求上,这样当客户端请求以 "/user/" 开头的 URL 时就会被 ControllerClassNameHandlerMapping 映射到 UserController 进行处理。
3. DefaultAnnotationHandlerMapping
DefaultAnnotationHandlerMapping 将请求的 URL 映射到带有特定注解的处理器方法上。例如,我们可以在 Controller 类中定义一个带有 @RequestMapping 注解的方法,并将该方法映射到 "/hello.html" 请求上,这样当客户端请求 "/hello.html" 时就会被 DefaultAnnotationHandlerMapping 映射到该方法进行处理。
4. SimpleUrlHandlerMapping
SimpleUrlHandlerMapping 将请求的 URL 映射到指定的处理器 Bean 上。与 BeanNameUrlHandlerMapping 类似,不同之处在于 SimpleUrlHandlerMapping 可以自定义 URL 和 Bean 的映射关系。
5. AbstractDetectingUrlHandlerMapping
AbstractDetectingUrlHandlerMapping 是一个抽象类,它提供了默认的 URL 和 Handler 映射规则,但我们也可以根据具体需求来实现自己的 URL 映射规则。
6. RequestMappingHandlerMapping
RequestMappingHandlerMapping 是 Spring MVC 中最常用的 HandlerMapping 实现,它将请求的 URL 映射到带有 @RequestMapping 注解的方法上,并支持各种参数绑定、数据格式转换等高级功能。
以上是 Spring MVC 中常见的几种 HandlerMapping 实现及其作用。在实际开发中,我们可以根据具体需求来选择合适的 HandlerMapping 实现方式。
mapping.getHandler(request);
获取处理器执行链的方法
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);
}
// Ensure presence of cached lookupPath for interceptors and others
if (!ServletRequestPathUtils.hasCachedPath(request)) {
initLookupPath(request);
}
// 获取拦截器集合和上面获取的HandlerMethod封装成处理器执行链
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
logger.debug("Mapped to " + executionChain.getHandler());
}
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;
}
getHandlerInternal(request);
根据请求url获取HandlerMethod
@Override
@Nullable
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 截取控制层形式的url
String lookupPath = initLookupPath(request);
// 加锁
this.mappingRegistry.acquireReadLock();
try {
// 根据url获取HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
// 释放锁
this.mappingRegistry.releaseReadLock();
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
// 寻找合适mapping
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// 如果没有找到 就去全部的url中遍历
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
// ......
// 当查询到多个Match 则进入异常处理(正常一种类型url只有对应一个控制层方法)
}
// 请求作用域中存放HandlerMethod
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
// 请求作用域中存放本次请求url地址
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.getHandlerMethod();
}
else {
return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
}
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));
}
}
}
getMatchMappings(mapping,request);
- 判断当前 Mapping 是否支持当前请求的 HTTP 方法,如果不支持则返回 null。
- 将当前 Mapping 中的 URL Pattern 解析成 AntPathMatcher 对象(AntPathMatcher 是 Spring 提供的一个通配符匹配类),然后使用 AntPathMatcher 进行 URL 匹配。
- 如果 URL 匹配成功,则返回当前 Mapping,否则返回 null。
需要注意的是,在进行 URL 匹配时,如果请求 URL 中包含占位符(例如{id}),则还需要做进一步的处理,将占位符所对应的值提取出来并存放到 HttpServletRequest 对象的 attribute 中,以便后面的控制器方法使用。
2、getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
// this.handlerAdapters 这里的四个适配器是在servlet init初始化MVC九大组件时创建的
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");
}
adaptor.supports(handler);
具体来说,在实现 HandlerAdapter 接口的类中,通常会定义一个 supports(Object handler) 方法,并在其中对处理器对象类型进行判断。如果当前的 HandlerAdapter 支持该类型的处理器对象,则返回 true;否则返回 false。
例如,RequestMappingHandlerAdapter 类实现了 HandlerAdapter 接口,并且其中的 supports(Object handler) 方法用于判断是否支持 @RequestMapping 注解标注的控制器方法。如果当前的 handler 参数是一个带有 @RequestMapping 注解的控制器方法,则返回 true;否则返回 false。
3、前置拦截器执行
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
// 已注册拦截器的preHandle方法。
HandlerInterceptor interceptor = this.interceptorList.get(i);
// 顺序执行所有的前置拦截器方法
if (!interceptor.preHandle(request, response, this.handler)) {
// 前置拦截器有一个返回false则执行后置拦截器方法
triggerAfterCompletion(request, response, null);
return false;
}
// 记录当前的拦截器index 如果出现异常 后置拦截器需要从index倒叙执行
this.interceptorIndex = i;
}
// 拦截器全部正常 程序正常执行
return true;
}
4、ha.handle(processedRequest, response, mappedHandler.getHandler());
AbstractHandlerMethodAdapter类中
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
RequestMappingHandlerAdapter 类中
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
// ......
// handleInternal的核心
mav = invokeHandlerMethod(request, response, handlerMethod);
// ......
return mav;
}
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) {
// a. 参数解析器
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
// b. 返回值处理器
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);
}
// c. 执行目标方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
a. 参数解析器argumentResolvers
确定将要执行的目标方法的每一个参数的值是什么
SpringMVC目标方法能写多少种参数类型。取决于参数解析器argumentResolvers。
this.argumentResolvers在afterPropertiesSet()方法内初始化
RequestMappingHandlerAdapter 的 afterPropertiesSet() 方法是在 Spring 容器初始化完毕并完成依赖注入后,由 Spring 框架自动调用的一个初始化方法。
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Nullable
private HandlerMethodArgumentResolverComposite argumentResolvers;
@Override
public void afterPropertiesSet() {
...
if (this.argumentResolvers == null) {//初始化argumentResolvers
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
...
}
//初始化了一堆的实现HandlerMethodArgumentResolver接口的参数对象
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
if (KotlinDetector.isKotlinPresent()) {
resolvers.add(new ContinuationHandlerMethodArgumentResolver());
}
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new PrincipalMethodArgumentResolver());
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
}
参数解析器接口HandlerMethodArgumentResolver方法:
// 用于在给定请求的上下文中将方法参数解析为参数值的策略接口
public interface HandlerMethodArgumentResolver {
/**
* 当前解析器是否支持解析这种参数
*/
boolean supportsParameter(MethodParameter parameter);
/**
* 解析参数
*/
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
b. 返回值处理器returnValueHandlers
this.returnValueHandlers在afterPropertiesSet()方法内初始化
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
@Override
public void afterPropertiesSet() {
...
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
//初始化了一堆的实现HandlerMethodReturnValueHandler接口的返回值参数对象
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ServletModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ServletModelAttributeMethodProcessor(true));
}
return handlers;
}
}
HandlerMethodReturnValueHandler接口:
// 策略接口,用于处理从处理程序方法的调用返回的值。
public interface HandlerMethodReturnValueHandler {
/**
* 当前解析器是否支持解析这种返回参数
*/
boolean supportsReturnType(MethodParameter returnType);
/**
* 通过向模型添加属性并设置视图或将ModelAndViewContainer.setRequestHandled标志设置为true来处理给定的返回值,以指示已直接处理响应。
*/
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
c. 执行目标方法
invokeAndHandle方法:
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 执行目标方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
...
try {
// returnValue存储起来
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
...
}
}
// InvocableHandlerMethod类的,ServletInvocableHandlerMethod类继承InvocableHandlerMethod类
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取方法的参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
...
return doInvoke(args);
}
@Nullable
protected Object doInvoke(Object... args) throws Exception {
//@RequestMapping的方法
Method method = getBridgedMethod();
ReflectionUtils.makeAccessible(method);
try {
if (KotlinDetector.isSuspendingFunction(method)) {
return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);
}
//通过反射调用
return method.invoke(getBean(), args);//getBean()指@RequestMapping的方法所在类的对象。
}
catch (IllegalArgumentException ex) {
...
}
catch (InvocationTargetException ex) {
...
}
}
}
args内容:
method内容:
如何确定目标方法每一个参数的值
重点分析ServletInvocableHandlerMethod的getMethodArgumentValues方法
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
...
@Nullable//InvocableHandlerMethod类的,ServletInvocableHandlerMethod类继承InvocableHandlerMethod类
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取方法的参数值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
...
return doInvoke(args);
}
//本节重点,获取方法的参数值
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
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);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
//查看resolvers是否有支持
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) {
....
}
}
return args;
}
}
首先通过getMethodParameters方法获取参数信息
再通过if (!this.resolvers.supportsParameter(parameter))解析器resolvers支不支持解析该参数
public boolean supportsParameter(MethodParameter parameter) {
return this.getArgumentResolver(parameter) != null;
}
resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
中遍历获取到参数解析器
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);
}
resolveArgument(parameter, mavContainer, webRequest, binderFactory);
中完成解析
5、post拦截器执行
只有前置拦截器是顺序执行,post和后置都是倒序执行
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
6、processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
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);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// 后置拦截器方法倒序执行
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
render(mv, request, response);
后续处理中,会先检查 ModelAndView 中的 View 属性是否为空,如果为空则说明该请求需要返回 JSON 数据。接着,会遍历已注册的 HttpMessageConverter 列表,找到支持处理 application/json 类型的转换器,并使用该转换器将 ModelAndView 中的数据转换为 JSON 格式的字符串。转换完毕后,再通过 HttpServletResponse 将该 JSON 数据写回到客户端。