Spring MVC源码解析
文章目录
1 Spring MVC基于XML配置开发
需要开发者手动去定义配置文件,处理器的配置、实现特定接口、视图的配置、包扫描等的配置…都是基于XML文件来完成。
Spring MVC核心组件。SpringMVC执行流程:
1.客户端浏览器发送请求给服务器中的前端控制器DispatcherServlet;
2.⽤户根据请求中的url路径,通过HandlerMapping处理器映射器,找到匹配的Controller;
3.HandlerMapping返回⼀个处理器执⾏链,包括N个拦截器与1个Controller的处理器。并把处理器执⾏链,返回
给前端控制器DispatcherServlet;
4.前端控制器DispatcherServlet得到处理器执⾏链之后,把Controller的Handler发送给HandlerAdapter处
理器适配器;
5.HandlerAdapter根据supports(Object handler)⽅法,也就是内部的匹配规则,判断该处理器Handler是否
实现了Controller接⼝;
6.Handler处理器找到具体的⽅法handler.handleRequest(request, response),根据请求执⾏Controller
类中的⽅法;
7.Controller类执⾏完毕,然后返回⼀个ModelAndView对象给Handler处理器;
8.Handler处理器把ModelAndView对象返回给HandlerAdapter;
9.HandlerAdapter把ModelAndView对象返回给前端控制器DispathcerServlet;
10.DispathcerServlet把ModelAndView对象传递给ViewResolver视图解析器,根据jsp⻚⾯的名称拼接路;
11.ViewResolver视图解析器返回给DispathcerServlet前端控制器;
12.DispathcerServlet拿到jsp路径,由web容器对jsp⻚⾯进⾏视图渲染;
13.Web容器把响应结果返回给浏览器
2 Spring MVC基于XML配置的实现
1.创建一个项目:springmvc_code。创建成Java企业级的项目。
- JSP本质上就是Servlet(组件)。
- 如果使用原生的Servlet响应网页给客户端,需要使用PrintWriter的write(“xxx”)或者是println(“xxx”)。
- 将HTML代码抽离出来,定义在其他的文件中,使用动态拼接渲染,最终响应给客户端。
- 在JSP文件中可以直接定义网页的代码结构。可以通过EL表达式、JSTL标签库来完成页面的动态数据加载。
- Tomcat在编译JSP文件(Hello.jsp)的时候,将JSP转化成一个Servlet组件(Hello_jsp.java - Java源文件)。最后经过JVM虚拟机将Servlet组件转化成一个字节码文件(Hello_jsp.class)。
2.创建了一个Hello.jsp文件。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>SpringMVC基于XML文件的配置开发</title>
</head>
<body>
<h1>SpringMVC基于XML文件的配置开发</h1>
<p>数据展示:${msg}</p>
</body>
</html>
3.编写Web.xml核心配置文件:配置DispacherServlet、配置编码设置、springmvc-servlet.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 1.注册Servlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<!-- 2.配置映射 -->
<servlet-mapping>
<!-- 上下定义的名称需要保持一致 -->
<servlet-name>springmvc</servlet-name>
<!-- 表示请求的url映射: "/"表示能够匹配浏览器提交过来的所有请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4.Servlet的原理是什么?
或者:
5.创建一个HelloController类。
package com.qf.springmvc_code.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义控制器类: SpringMVC框架提供的一个接口Controller
*/
public class HelloController implements Controller { // URL访问地址基于XML配置的方式进行开发
/**
* 该方法什么时候被调用?
* 1.请求的url找了到了对象的Controller类之后,此Controller类中的handleRequest()方法会被自动回调。
* 2.ModelAndView: 模型和视图。
* - 模型:表示数据,可以在ModelAndView对象上绑定数据。
* - 视图:表示一个数据展示的页面,例如是一个JSP页面。
*/
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
/**
* 需求:配置的请求地址是"/hello",一旦访问该请求,服务器打开Hello.jsp文件,然后该jsp文件输出"Hello SpringMVC"信息。
*/
// 1.创建一个模型和视图对象
ModelAndView modelAndView = new ModelAndView();
// 2.在modelAndView对象上绑定数据(key-value键值对)
modelAndView.addObject("msg", "Hello Spring MVC");
/**
* 3.设置视图:表示将来跳转到那一个指定的视图页面(Hello.jsp页面)
* - 前缀:/WEB-INF/
* - 后缀:.jsp
*/
modelAndView.setViewName("hello"); // 表示访问的是/WEB-INF/hello.jsp页面
// 4.将模型和视图对象返回给调用者
return modelAndView;
}
}
6.Controller接口分析:
@FunctionalInterface // 函数式接口
public interface Controller {
// 用来处理请求和响应(request和response对象会自动的传递给此方法)
@Nullable
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
7.默认情况下,SpringMVC框架自动去/WEB-IN/springmvc-servlet.xml此配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 1.注册处理器映射器:HandlerMapping
作用:处理器映射器会根据请求的url地址,将url和Spring容器中的一个bean的name属性值进行匹配。
说明:bean标签没有显示的什么id属性的取值,Spring容器会自动的为其分配一个id的值(自定生成),
id生成规则是:包名.类名#数字。例如:id=com.qf.springmvc_code.controller.HelloController#1 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 2.注册处理器(HelloController类)
name属性:表示对应一个前端的请求,name属性的取值必须使用"/"开头
class属性:表示对应请求从DispatcherServlet发送过来的请求,对应的的后台处理器 -->
<bean name="/hello" class="com.qf.springmvc_code.controller.HelloController"></bean>
<!-- 3.配置处理器适配器:HandlerAdapter
作用:根据HandlerMapping返回的Controller,执行一个匹配的规则,主要是找到对应的Handler去处理Controller。 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 4.配置视图解析器:ViewResolver
作用:根据路径的前缀和后缀找到对应的视图文件,然后进行渲染 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 4.1 配置资源文件的路径前缀 -->
<property name="prefix" value="/WEB-INF/"></property> <!-- 表示给一个属性配置初始化取值的数据 -->
<!-- 4.2 配置资源文件的后缀(文件扩展名称) -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
8.启动服务器,访问项目。
3 SpringMVC源码解析
3.1 前端控制器DispatcherServlet
1.继承关系:
DispatcherServlet继承 - FrameworkServlet继承 - HttpServletBean继承 - HttpServlet继承 - GenericServlet结成 - Servlet接口。
2.DispatcherServlet前端控制器:等待请求和响应,一个方法doDispatch()。
// Servlet接口中提供的一个方法,根据不同的请求类型来进行请求的处理
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ...
// 调用了doDispatch()方法,传递了请求和响应对象
this.doDispatch(request, response);
}
3.doDispatch方法定义。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
// 创建一个处理器执行链(将来执行请求的流程)
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 通过getHandler(request)返回一个处理器执行链对象
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.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;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
4.查看getHandler(processedRequest)的源码。
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) { // 维护的是url和Controller的映射
Iterator var2 = this.handlerMappings.iterator();
// HandlerMapping是Servlet所支持的处理器映射器的一个集合,这里可能会有N个处理器映射器
while(var2.hasNext()) {
// 举例:/hello - HelloController对象
HandlerMapping mapping = (HandlerMapping)var2.next(); // url映射Controller
// 返回一个处理器执行链
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
5.查看getHandler(request)方法的源码。HandlerMapping接口有一个实现类:AbstractHandlerMapping类。
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 获取一个Handler对象
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
if (!ServletRequestPathUtils.hasCachedPath(request)) {
this.initLookupPath(request);
}
// 获取处理器执行链。根据request请求对象和一个处理器Handler对象来获取处理器执行链
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Mapped to " + handler);
} else if (this.logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
this.logger.debug("Mapped to " + executionChain.getHandler());
}
if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = this.getCorsConfiguration(handler, request);
if (this.getCorsConfigurationSource() != null) {
CorsConfiguration globalConfig = this.getCorsConfigurationSource().getCorsConfiguration(request);
config = globalConfig != null ? globalConfig.combine(config) : config;
}
if (config != null) {
config.validateAllowCredentials();
}
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
6.查看getHandlerInternal(request)方法。
// 获取一个Controller
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
7.查看getHandlerExecutionChain(handler, requst)方法。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 获取一个处理器执行链对象
HandlerExecutionChain chain =
handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
Iterator var4 = this.adaptedInterceptors.iterator();
while(var4.hasNext()) {
HandlerInterceptor interceptor = (HandlerInterceptor)var4.next();
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
// request:对象中就有目标的url地址,例如是/hello
// HandlerMapping获取的映射,url得知
if (mappedInterceptor.matches(request)) {
// 这里可以看出具有多个拦截器,而且拦截器根据请求做匹配
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
// 处理器执行链:包含两部分内容。interceptor和handler。
return chain;
}
DispathcherServlet前端控制器,经过一系列的处理返回一个处理器执行链对象(HandlerExecutionChain)。在该对象封装了两部信息,分别是Interceptor拦截器和一个Handler处理器。
8.配置初始化参数信息。
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 给当前的Servlet配置初始化参数:配置的是springmvc框架的核心配置文件的位置 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc-servlet.xml</param-value>
</init-param>
</servlet>
9.XmlWebApplicationContext类维护了SpringMVC的核心配置文件的加载。
/**
* The default location for the root context is "/WEB-INF/applicationContext.xml",
* and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet"
* (like for a DispatcherServlet instance with the servlet-name "test").
* 项目的根目录的上下文位置"/WEB-INF/applicationContext.xml"找核心配置文件。或者通过"/WEB-INF/test-servlet.xml"路径来找配置文件,规则是:通过DispacherServlet的name属性的取值,来进行获取文件的,在name属性的取值后自动添加"-servlet"作为被寻找的配置文件名称。
*/
@Override
protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
else {
return new String[] {DEFAULT_CONFIG_LOCATION};
}
}
3.2 处理器映射器HandlerMapping
HandlerMapping接口负责将request对象和请求找到的Handler对象及interceptor对象,封装到处理器执行链(HandlerExcecationChain)中,返回给前端控制器(DispacherSerlvet)。
HandlerMapping接口提供了两个实现类:
- BeanNameUrlHandlerMapping
- SimpleUrlHandlerMapping
1.BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping处理器映射器会根据请求的url与Spring中定义Controller的name属性的取值进行匹配(Spring容器中定义的Bean类的name属性进行匹配)。如果匹配成功,则返回一个处理器对象(Controller对象)。
1.xml文件中的配置。
<!-- 1.注册处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 2.注册处理器(Controller) -->
<bean name="/hello" class="com.qf.springmvc_code.controller.HelloController"></bean>
2.BeanNameUrlHandlerMapping类的源码解析。
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
// 构造方法
public BeanNameUrlHandlerMapping() {
}
// 检查给定的bean的name属性的取值是否以“/”开头,如果是,则添加到String[]数组中了
protected String[] determineUrlsForHandler(String beanName) { // name="/hello"
List<String> urls = new ArrayList(); // List集合是用来存储url的(name属性的值的集合)
if (beanName.startsWith("/")) { // 判断name属性的取值是否以"/"开头
urls.add(beanName); // 将这个name的取值添加到List集合中
}
String[] aliases = this.obtainApplicationContext().getAliases(beanName);
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
if (alias.startsWith("/")) {
urls.add(alias); // 如果bean别名以“/”开头,则将别名添加到List集合中
}
}
// List<String> 转化成 String[]
return StringUtils.toStringArray(urls);
}
}
3.需求:
- 访问 /hello,可以打开HelloController。
- 访问/world,可以打开HelloController。
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<bean name="/hello" class="com.qf.springmvc_code.controller.HelloController"></bean>
<bean name="/world" class="com.qf.springmvc_code.controller.HelloController"></bean>
4.BeanNameUrlHandlerMapping缺点:
- 注册处理器的时候,如果有多个url映射同一个Controller,代码极为冗余。
- Controller处理器url要求不能重复,而bean标签name属性的值是可以重复。如果就显得不伦不类。
2.SimpleUrlHandlerMapping
SimpleUrlHandlerMapping实现方式分为两种。
<!--1.注册处理器映射器:SimpleUrlHandlerMapping -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<!-- 方式2:urlMap的属性来实现请求地址的映射-->
<property name="urlMap">
<map>
<!-- entry表示表示一组url与Controller的映射。key表示请求的url地址,value表示Controller的bean标签对应的id属性的值 -->
<entry key="/hello" value="helloController" />
<entry key="/world" value="helloController" />
</map>
</property>
<!-- 方式1:通过mappings属性完成的-->
<!--
mappings属性:通过mappings属性来为当前的处理器同时配置多个url地址的请求映射
<property name="mappings">
<props>
prop表示声明一组url的映射,其中key表示配置请求地址,prop标签的内容是Controller的bean的id取值
<prop key="/hello">helloController</prop>
<prop key="/world">helloController</prop>
</props>
</property>
-->
</bean>
<!--2.注册处理器: HelloController-->
<bean id="helloController" class="com.qf.springmvc_code.controller.HelloController"></bean>
3.HandlerMapping的源码解析
1.DispacherServlet类中doService(request, response)。
this.doDispatch(request, response);
2.doDispatch(request, response)方法。需要接受一个request请求对象。
mappedHandler = this.getHandler(processedRequest);
3.getHandler(processedRequest)方法。
// List集合中存放的是所有的HandlerMapping对象
@Nullable
private List<HandlerMapping> handlerMappings;
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
// 遍历HandlerMappings的集合
while(var2.hasNext()) {
// 获取一个HandlerMapping类型的对象
HandlerMapping mapping = (HandlerMapping)var2.next();
// 通过request请求来获取HandlerMapping处理器执行链
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
4.getHandler(request)方法。是在AbstractHandlerMapping中实现了该方法。
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据请求对象获取一个处理器
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
if (!ServletRequestPathUtils.hasCachedPath(request)) {
this.initLookupPath(request);
}
// 根据request和response对象来获取一个处理器执行链(HandlerExecutionChain)
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Mapped to " + handler);
} else if (this.logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
this.logger.debug("Mapped to " + executionChain.getHandler());
}
if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = this.getCorsConfiguration(handler, request);
if (this.getCorsConfigurationSource() != null) {
CorsConfiguration globalConfig = this.getCorsConfigurationSource().getCorsConfiguration(request);
config = globalConfig != null ? globalConfig.combine(config) : config;
}
if (config != null) {
config.validateAllowCredentials();
}
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
5.getHandlerExecutionChain()方法。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 实例化一个HandlerExecutionChain对象
HandlerExecutionChain chain =
handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
Iterator var4 = this.adaptedInterceptors.iterator();
while(var4.hasNext()) {
// 创建一个处理器过滤器对象
HandlerInterceptor interceptor = (HandlerInterceptor)var4.next();
if (interceptor instanceof MappedInterceptor) {
// 转化成一个MappedInterceptor过滤器
MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
if (mappedInterceptor.matches(request)) { // 判断请求对象中的url和配置是否相同
// 把这个过滤器添加到HandlerExecutionChain对象中
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
// 返回一个HandlerExecutionChain对象:handler、interceptor(request)
return chain;
}
HandlerMapping处理器映射器,通过源码分析返回一个HandlerExecutionChain的对象(包含了url和Controller的映射)。
3.3 处理器适配器HandlerAdapater
1.HandlerAdapater源码分析
1.找到DispacherSerlvet类中doService方法。
this.doDispatch(request, response);
2.查看doDispatch(request, response)方法。
// doDispatch(request, response)方法中中getHandlerAdapter方法返回一个HandlerAdapater对象
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
3.getHandlerAdapter(mappedHandler.getHandler())方法。
// 方法通过Handler对象来返回一个HandlerAdapter对象
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) { // List<HandlerAdapter>集合中
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
// 获取集合中的HandlerAdapter对象
HandlerAdapter adapter = (HandlerAdapter)var2.next();
if (adapter.supports(handler)) { // 调用HandlerAdapter的supports方法
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
4.supports(handler)方法。方式是有SimpleControllerHandlerAdapter类实现的。
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
// 构造方法
public SimpleControllerHandlerAdapter() {
}
// 传递的Handler对象是HelloController
// HelloController类的定义public class HelloController implements Controller
public boolean supports(Object handler) {
// 通过传递过来的Handler对象,判断该对象是否是Controller类型
return handler instanceof Controller;
}
/**
* 参数1:表示一个request请求对象
* 参数2:表示一个response请求对象
* 参数3:表示一个Controller对象(HelloController)
*/
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 多态:向上转型。调用handleRequest(request, response)方法来完成请求处理业务逻辑
return ((Controller)handler).handleRequest(request, response);
}
// 与HttpSerlvet的getLastModified方法的约定时间。
public long getLastModified(HttpServletRequest request, Object handler) {
return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
}
}
2.HandlerAdapter的执行
DispacherServlet会根据HandlerMapping传递回来的Controller注册到以配置的HandlerAdapter上。HandlerAdapater来判断Controller的数据类型是否满足满足要求(Controller), 如果类型满足要求,则将该Controller进行类型转化(Controller接口类型)。调用目标Controller的HandleRequest(request, response)方法,来完成目标业务逻辑方法的调用。
3.4 视图解析器ViewResolver
1.ViewResolver源码分析
1.InternalResourceViewResolver类的定义。
public class InternalResourceViewResolver extends UrlBasedViewResolver {
// 通过JSTL标签库来解析目标JSP文件
private static final boolean jstlPresent =
ClassUtils.isPresent(
// 加载JSTL的标签标签库
"javax.servlet.jsp.jstl.core.Config",
// 获取当前类的类加载器
InternalResourceViewResolver.class.getClassLoader());
// ...
}
2.UrlBasedViewResolver类。
public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {
public static final String REDIRECT_URL_PREFIX = "redirect:"; // 重定向
public static final String FORWARD_URL_PREFIX = "forward:"; // 转发
@Nullable
private Class<?> viewClass;
private String prefix = ""; // 目标视图的前缀(在那一个目录下存放的)
private String suffix = ""; // 目标视图的后缀(.jsp、.asp)
}
2.ViewResolver流程
1.将SpringMVC框架的前端控制器中的返回结果封装成一个ModelAndView对象。
2.通过视图解析器,将返的ModelAndView对象进行解析,解析成一个物理地址的映射视图。
3.将这个物理地址的视图通过View接口来进行渲染。