Spring 源码解析一:SpringMVC 的加载机制
source link: https://segmentfault.com/a/1190000040786453
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Spring 源码解析一:SpringMVC 的加载机制
1. spring-framework
包含的模块
在解析 SpringMVC
的加载机制之前,先来看看官方 spring-framework
包含有哪些模块,各有什么用。
spring-jcl
:spring
框架的通用日志处理spring-core
:spring
框架的核心机制模块,包括 Java 字节码的操作处理与动态生成、依赖注入机制(也叫控制反转)、工具类库、
注解操作、编码处理与数据转换、资源加载与处理、环境加载机制等spring-beans
:spring bean
的定义、加载、解析、编辑等spring-context
:spring
框架的上下文环境,包括应用缓存、应用事件、应用配置、核心注解定义与处理、资源加载、异步与定时任务、数据验证与格式化等spring-aop
:面向切面编程的封装与处理spring-aspects
:使用 AspectJ 作为底层实现的面向切面编程spring-tx
:事务的封装与处理spring-jdbc
:数据库链接的封装与处理spring-context-indexer
:对注解@Indexed
的支持spring-context-support
:对一些第三方库的可选支持,如ehcache, javamail, quartz, freemarker
spring-oxm
:对 O/X Mapper 的封装spring-messaging
:对http, rsocket, simp
等消息传递协议的封装spring-jms
:对 JMS(Java 消息服务) 的封装spring-expression
:Spring Expression Language (SpEL) Spring 表达式语言的实现spring-r2dbc
:对 R2DBC 的封装spring-orm
:对 JPA 和 hibernate 的封装spring-web
:提供了 Web 框架的基础结构与技术,如 Http 的调用、过滤、处理等spring-webmvc
:Web MVC 架构的实现,包括 Servlet 容器初始化、路由映射、视图渲染、响应处理等spring-websocket
:对 WebSocket 的支持spring-webflux
:Reactive Web 框架的实现,与spring-webmvc
相对
SpringMVC 框架的核心模块主要是:spring-core
、spring-beans
、spring-context
、spring-web
、spring-webmvc
,后面也主要从这几个模块来分析。
1.1. spring-core
spring-core
的核心功能有几点需要在这里简单介绍一下:
spring-core
有强大的 Java 字节码操作处理功能与动态生成功能,这是面向切面编程、数据类型转换、SpEL 表达式等功能的基础spring-core
提供了依赖注入机制,这是spring bean
加载的基础,也是我们可以使用@Autowired
自动装载对象等功能的底层机制spring-core
提供了环境加载的机制,所以我们可以使用application-dev.yml, application-test.yml, application-prod.yml, ...
来根据环境加载不同的配置spring-core
提供了一个类似 Java SPI 的的扩展机制,可以自动实例化其他包指定的类,spring-boot, spring-cloud
都依赖这个机制自动加载资源。
在META-INF/spring.factories
文件中定义需要自动加载的类,详细介绍可以参考 Spring Factories
1.2. spring-beans
Spring bean 的加载与扩展机制有几点需要在这里简单介绍一下:
- Spring bean 的定义主要是两种:基于注解的定义、基于 XML 文件的定义
spring-beans
提供了基于 XML 配置的、第三方对 bean 的自定义扩展机制,主要是在META-INF/spring.handlers, META-INF/spring.schemas
文件中定义需要扩展的标签,比如<dubbo:application name="name"/>, <dubbo:registry address="address"/>
- 基于注解的自定义扩展,需要依赖
spring-boot
的扩展加载机制
1.3. spring-context
spring-context
是应用的核心处理部分,包括:
- 核心注解定义与处理
- 异步与定时任务
- 数据验证与格式化
等,@ComponentScan, @Profile, @Conditional, @Bean, @Async, @Controller, @Service, @Component, @Validated
等这类框架核心注解便是在这里定义的。
1.4. spring-web
spring-web
是 Http 的核心处理部分,主要包含:
- 核心 Http 请求与响应处理(包括 Cookie、缓存、多媒体等)
- Http 请求与响应编解码与转换(包括 Json、XML、ProtoBuf 等)
- Reactive Web 框架基础处理
- 调用客户端(如
RestTemplate
) - Servlet 上下文环境
- 请求过滤器
- Multipart 文件上传处理
等,@RequestMapping, @RequestParam, @PathVariable, @ResponseBody, @RestController
等这类 Web 核心注解便是在这里定义的。
1.5. spring-webmvc
spring-webmvc
依赖于 spring-web
,主要功能包括:
- Servlet 容器初始化
等,如果不使用 Spring MVC ,但想要借助其它 Spring 支持的 web 相关技术的优势,那么只需依赖 spring-web
,如 spring-webflux
。
1.6. spring-webflux
spring-webflux
与 spring-webmvc
相对应,webmvc
是同步阻塞框架,而 webflux
是异步非阻塞框架,是 Spring Framework 5.0 中引入的新的响应式 web 框架。
参考:Spring WebFlux 入门、Spring WebFlux :: Spring Docs
2. 一个简单的 spring-webmvc
项目配置
在 WEB-INF/web.xml
文件中如下配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>springMVC</display-name>
<!-- 部署 DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 容器再启动时立即加载servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 处理所有URL -->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 定义应用程序监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
这里有两个入口类:
这两个类分别定义在 spring-webmvc
与 spring-web
中,下面对他们一一进行解析。
3. DispatcherServlet
先来看看 DispatcherServlet
的继承关系:
- javax.servlet.Servlet
- javax.servlet.GenericServlet
- javax.servlet.http.HttpServlet
- HttpServletBean
- FrameworkServlet
- DispatcherServlet
3.1. javax.servlet.Servlet
javax.servlet.Servlet
主要定义了 2 个方法:
init
:初始化 Servlet,只执行一次service
:响应请求,每次 http 请求都会调用这个方法
public interface Servlet {
// 初始化 Servlet,只执行一次
public void init(ServletConfig config) throws ServletException;
// 响应请求,每次http请求都会调用这个方法
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
// 销毁 Servlet
public void destroy();
}
3.2. javax.servlet.GenericServlet
再来看看 javax.servlet.GenericServlet
javax.servlet.GenericServlet
主要是重载了 init
方法
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable {
public GenericServlet() {}
// 添加配置初始化
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
// 保留无参初始化
public void init() throws ServletException {}
// 留给子类实现
public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
}
3.3. javax.servlet.http.HttpServlet
再来看看 javax.servlet.http.HttpServlet
javax.servlet.http.HttpServlet
主要是重载了 service
方法,并扩展了 7 个方法:
doGet
:处理 GET 请求,只输入错误信息,未实现doHead
:处理 HEAD 请求,只输入错误信息,未实现doPost
:处理 POST 请求,只输入错误信息,未实现doPut
:处理 PUT 请求,只输入错误信息,未实现doDelete
:处理 DELETE 请求,只输入错误信息,未实现doOptions
:处理 OPTIONS 请求doTrace
:处理 TRACE 请求
public abstract class HttpServlet extends GenericServlet {
private static final String METHOD_DELETE = "DELETE";
private static final String METHOD_HEAD = "HEAD";
private static final String METHOD_GET = "GET";
private static final String METHOD_OPTIONS = "OPTIONS";
private static final String METHOD_POST = "POST";
private static final String METHOD_PUT = "PUT";
private static final String METHOD_TRACE = "TRACE";
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,但body设为空body
doGet(req, response);
response.setContentLength();
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ... 代码省略
}
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ... 代码省略
}
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ... 代码省略
}
protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ... 代码省略
}
protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ... 代码省略
}
// 实现了GET, HEAD, POST PUT, DELETE, OPTIONS, TRACE七个Http方法
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
// ... 代码省略
doGet(req, resp);
// ... 代码省略
} 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 {
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);
}
}
// 把 Servlet 转化为 HttpServlet
@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");
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);
}
}
3.4. HttpServletBean
再来看看 HttpServletBean
HttpServletBean
主要是重载了 init
方法,并扩展了 2 个方法:
initBeanWrapper
:初始化由 Servlet Config 定义的 Java Bean,由子类实现,默认不实现initServletBean
:初始化 Servlet bean,由子类实现
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
// 初始化
@Override
public final void init() throws ServletException {
// Set bean properties from init parameters.
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;
}
}
// Let subclasses do whatever initialization they like.
initServletBean();
}
// 初始化由Servlet Config定义的Java Bean,由子类实现,默认不实现
protected void initBeanWrapper(BeanWrapper bw) throws BeansException {
}
// 初始化Servlet bean,由子类实现
protected void initServletBean() throws ServletException {
}
}
3.5. FrameworkServlet
再来看看 FrameworkServlet
FrameworkServlet
是框架的核心 Servlet,主要是重载了 initServletBean
方法,并扩展了 2 个方法:
initFrameworkServlet
:初始化框架 Servlet,由子类实现,默认不实现onRefresh
:刷新上下文数据,由子类实现
重载了 service, doGet, doPost, doPut, doDelete, doOptions, doTrace
方法,并扩展了 1 个方法:
doService
:处理响应请求
3.5.1. FrameworkServlet.initServletBean
父类 HttpServletBean
初始化后,留下两个钩子 initBeanWrapper, initServletBean
,initBeanWrapper
默认并不实现,所以来看看 initServletBean
钩子的实现:FrameworkServlet.initServletBean
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
@Override
protected final void initServletBean() throws ServletException {
// ... 代码省略
try {
// 初始化Web应用上下文
this.webApplicationContext = initWebApplicationContext();
// 初始化Web框架Servlet
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
// ... 代码省略
}
// 初始化框架Servlet,由子类实现,默认不实现
protected void initFrameworkServlet() throws ServletException {}
}
再来看看 FrameworkServlet.initWebApplicationContext
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
protected WebApplicationContext initWebApplicationContext() {
// 获取应用根上下文
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
// 未激活
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
// 配置并刷新应用上下文
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// 如果没有,则在ServletContext中查找是否注册过
wac = findWebApplicationContext();
}
if (wac == null) {
// 如果任然没有,则以rootContext为父上下文创建一个新的上下文
// 并调用 configureAndRefreshWebApplicationContext(cwac) 配置并刷新新的上下文
// 默认使用 XmlWebApplicationContext(基于XML加载)作为应用上下文
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// 重载上下文数据
synchronized (this.onRefreshMonitor) {
onRefresh(wac);
}
}
if (this.publishContext) {
// 把上下文注册到ServletContext中
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
// 以parent为父上下文创建一个新的上下文
// 并调用 configureAndRefreshWebApplicationContext(cwac) 配置并刷新新的上下文
// 默认使用 XmlWebApplicationContext(基于XML加载)作为应用上下文
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
// 这里默认使用 XmlWebApplicationContext(基于XML加载)
Class<?> contextClass = getContextClass();
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
configureAndRefreshWebApplicationContext(wac);
return wac;
}
}
这其中有两个方法需要深入解析:configureAndRefreshWebApplicationContext
, onRefresh
再来看看 FrameworkServlet.configureAndRefreshWebApplicationContext
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
// ... 代码省略
// 设置ServletContext
wac.setServletContext(getServletContext());
// 设置ServletConfig
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
// 添加应用事件监听器,应用事件会触发当前对象的onApplicationEvent方法
// 进一步,会调用当前对象的onRefresh方法,刷新上下文数据
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// ... 代码省略
// 初始化一些需要初始加载的类,调用这些类的initialize方法
applyInitializers(wac);
// 应用上下文刷新
wac.refresh();
}
// 应用事件会触发此方法,然后调用当前对象的onRefresh方法,刷新上下文数据
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
synchronized (this.onRefreshMonitor) {
onRefresh(event.getApplicationContext());
}
}
}
再来看看 FrameworkServlet.onRefresh
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
protected void onRefresh(ApplicationContext context) {
// 由子类来实现
}
}
3.5.2. FrameworkServlet.service
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
// 如果Http方法是Patch或没有,扩展处理
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
@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);
}
@Override
protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 扩展处理
processRequest(request, response);
}
@Override
protected void doOptions(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) {
// 扩展处理
processRequest(request, response);
if (response.containsHeader("Allow")) {
// Proper OPTIONS response coming from a handler - we're done.
return;
}
}
// ... 代码省略
}
@Override
protected void doTrace(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (this.dispatchTraceRequest) {
// 扩展处理
processRequest(request, response);
if ("message/http".equals(response.getContentType())) {
// Proper TRACE response coming from a handler - we're done.
return;
}
}
super.doTrace(request, response);
}
}
再来看看扩展处理方法 FrameworkServlet.processRequest
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// ... 代码省略
// 记录请求属性与上下文环境,请求处理完后派发事件
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);
}
// ... 代码省略
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
// 由子类来实现
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
3.6. DispatcherServlet
DispatcherServlet
主要扩展了 2 个方法:onRefresh
、doService
,所以来看看 DispatcherServlet 是如何实现的
3.6.1. DispatcherServlet.onRefresh
public class DispatcherServlet extends FrameworkServlet {
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
// 初始化Multipart文件上传处理
initMultipartResolver(context);
// 初始化本地化处理
initLocaleResolver(context);
// 初始化主题处理
initThemeResolver(context);
// 初始化处理器映射
initHandlerMappings(context);
// 初始化处理器适配
initHandlerAdapters(context);
// 初始化处理器异常
initHandlerExceptionResolvers(context);
// 初始化视图查找处理
initRequestToViewNameTranslator(context);
// 初始化视图解析处理
initViewResolvers(context);
// 初始化内存暂存session数据管理器
initFlashMapManager(context);
}
private void initMultipartResolver(ApplicationContext context) {
try {
// 获取bean
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
// ... 代码省略
}
catch (NoSuchBeanDefinitionException ex) {
// ... 代码省略
}
}
private void initLocaleResolver(ApplicationContext context) {
try {
// 获取bean
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
// ... 代码省略
}
catch (NoSuchBeanDefinitionException ex) {
// ... 代码省略
}
}
private void initThemeResolver(ApplicationContext context) {
try {
// 获取bean
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
// ... 代码省略
}
catch (NoSuchBeanDefinitionException ex) {
// ... 代码省略
}
}
private void initFlashMapManager(ApplicationContext context) {
try {
// 获取bean
this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
}
catch (NoSuchBeanDefinitionException ex) {
// 没有bean,则获取默认策略
this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
}
}
}
3.6.1.1. DispatcherServlet.initHandlerMappings
DispatcherServlet.initHandlerMappings
public class DispatcherServlet extends FrameworkServlet {
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 默认是探测所有的HandlerMapping,包括父上下文
if (this.detectAllHandlerMappings) {
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
// 否则直接获取bean
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {}
}
// 如果以上两种都没有定义,则获取默认的处理策略
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
// ... 代码省略
}
// 获取默认的处理策略
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
// 尝试从DispatcherServlet.properties文件中加载
if (defaultStrategies == null) {
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length);
for (String className : classNames) {
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
// 创建bean
Object strategy = createDefaultStrategy(context, clazz);
// 装载到 strategies 中
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
// ... 代码省略
}
catch (LinkageError err) {
// ... 代码省略
}
}
return strategies;
}
else {
return Collections.emptyList();
}
}
// 创建bean
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
return context.getAutowireCapableBeanFactory().createBean(clazz);
}
}
DispatcherServlet.properties 文件(开发者不能自定义覆盖)如下:
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
org.springframework.web.servlet.function.support.RouterFunctionMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
org.springframework.web.servlet.function.support.HandlerFunctionAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
DispatcherServlet.properties
文件中指明:
- 把
AcceptHeaderLocaleResolver
作为默认的本地化解析器 - 把
FixedThemeResolver
作为默认的主题解析器 - 把
BeanNameUrlHandlerMapping, RequestMappingHandlerMapping, RouterFunctionMapping
作为默认的处理器映射组件 - 把
HttpRequestHandlerAdapter, SimpleControllerHandlerAdapter, RequestMappingHandlerAdapter, HandlerFunctionAdapter
作为默认的处理器适配组件 - 把
ExceptionHandlerExceptionResolver, ResponseStatusExceptionResolver, DefaultHandlerExceptionResolver
作为默认的处理器异常解析器 - 把
DefaultRequestToViewNameTranslator
作为默认的视图查找处理器 - 把
InternalResourceViewResolver
作为默认的视图解析器 - 把
SessionFlashMapManager
作为默认的内存暂存 session 数据管理器
3.6.1.2. DispatcherServlet.initHandlerAdapters
DispatcherServlet.initHandlerAdapters
public class DispatcherServlet extends FrameworkServlet {
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
// 默认是探测所有的HandlerAdapter,包括父上下文
if (this.detectAllHandlerAdapters) {
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
// 否则直接获取bean
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {}
}
// 如果以上两种都没有定义,则获取默认的处理策略
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
}
}
}
3.6.1.3. DispatcherServlet.initHandlerExceptionResolvers
DispatcherServlet.initHandlerExceptionResolvers
public class DispatcherServlet extends FrameworkServlet {
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
// 默认是探测所有的HandlerExceptionResolver,包括父上下文
if (this.detectAllHandlerExceptionResolvers) {
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
else {
// 否则直接获取bean
try {
HandlerExceptionResolver her =
context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
}
catch (NoSuchBeanDefinitionException ex) {}
}
// 如果以上两种都没有定义,则获取默认的处理策略
if (this.handlerExceptionResolvers == null) {
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
}
}
}
3.6.1.4. DispatcherServlet.initRequestToViewNameTranslator
DispatcherServlet.initRequestToViewNameTranslator
public class DispatcherServlet extends FrameworkServlet {
private void initRequestToViewNameTranslator(ApplicationContext context) {
try {
// 获取bean
this.viewNameTranslator =
context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
}
catch (NoSuchBeanDefinitionException ex) {
// 如果没有定义bean,则获取默认的处理策略
this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
}
}
}
3.6.1.5. DispatcherServlet.initViewResolvers
DispatcherServlet.initViewResolvers
public class DispatcherServlet extends FrameworkServlet {
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
// 默认是探测所有的ViewResolver,包括父上下文
if (this.detectAllViewResolvers) {
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
}
else {
// 否则直接获取bean
try {
ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
}
catch (NoSuchBeanDefinitionException ex) {}
}
// 如果以上两种都没有定义,则获取默认的处理策略
if (this.viewResolvers == null) {
this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
}
}
}
3.6.2. DispatcherServlet.doService
刚刚解析完了 DispatcherServlet.onRefresh
,现在来看看 DispatcherServlet.doService
public class DispatcherServlet extends FrameworkServlet {
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ... 代码省略
// 给请求对象添加一些上下文数据
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());
// ... 代码省略
try {
doDispatch(request, response);
}
finally {
// ... 代码省略
}
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
// 处理器链
HandlerExecutionChain mappedHandler = null;
// 是Multipart文件上传
boolean multipartRequestParsed = false;
// 异步处理管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 检测Multipart文件上传
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取处理器,从handlerMappings中查找符合请求的处理器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 未找到处理器,404
noHandlerFound(processedRequest, response);
return;
}
// 获取处理器适配器,从handlerAdapters中查找符合处理器的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
// 如果是GET或HEAD请求,检查Last-Modified
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 前置处理,调用处理器的preHandle方法,如果有一个不成功,返回
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 调用处理器
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// ... 代码省略
// 如果没有视图名字,添加默认的视图名
applyDefaultViewName(processedRequest, mv);
// 后置处理,调用处理器的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
// ... 代码省略
}
catch (Throwable err) {
// ... 代码省略
}
// 处理handler返回的结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// ... 代码省略
}
catch (Throwable err) {
// ... 代码省略
}
finally {
// ... 代码省略
}
}
// 处理handler返回的结果
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
// ... 代码省略,如果有异常,调用handlerExceptionResolvers处理
}
if (mv != null && !mv.wasCleared()) {
// 渲染视图
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
// ... 代码省略
}
// 渲染视图
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// ... 代码省略
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// 调用viewResolvers来解析视图
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
// ... 代码省略
}
else {
// ... 代码省略
}
// ... 代码省略
try {
if (mv.getStatus() != null) {
// 设置http状态码
response.setStatus(mv.getStatus().value());
}
// 真实渲染
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
// ... 代码省略
}
}
}
3.6.3. 需要后面再解析的几个点
DispatcherServlet
这个类的解析基本上就差不多了,但还有几点没有解析:
这几点,我们后面再来解析。
4. ContextLoaderListener
先来看看 ContextLoaderListener
的继承关系:
- ContextLoader
- ContextLoaderListener
ContextLoaderListener 比较简单,只有两个监听事件方法
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
// ContextLoader.initWebApplicationContext
initWebApplicationContext(event.getServletContext());
}
@Override
public void contextDestroyed(ServletContextEvent event) {
// ContextLoader.closeWebApplicationContext
closeWebApplicationContext(event.getServletContext());
// 销毁上下文中以"org.springframework."开头的可销毁bean
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
ContextLoader 的静态初始化
public class ContextLoader {
static {
try {
// 从ContextLoader.properties文件中加载默认的策略
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
}
}
}
ContextLoader.properties 文件的内容如下:
# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
ContextLoader.properties
文件中指明使用 XmlWebApplicationContext
作为默认的 Web 应用上下文环境
再来看看 ContextLoader 的 initWebApplicationContext
和 closeWebApplicationContext
4.1. ContextLoaderListener.initWebApplicationContext
ContextLoaderListener.initWebApplicationContext
public class ContextLoader {
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
// ... 代码省略
try {
// 如果没有上下文对象,则创建一个新的上下文
// 并调用 configureAndRefreshWebApplicationContext(cwac) 配置并刷新新的上下文
// 默认使用 XmlWebApplicationContext(基于XML加载)作为应用上下文
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
// 未激活
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
// 配置并刷新应用上下文
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
// 把上下文注册到ServletContext中
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
// ... 代码省略
return this.context;
}
catch (RuntimeException | Error ex) {
// ... 代码省略
}
}
}
ContextLoader.configureAndRefreshWebApplicationContext
与 FrameworkServlet.configureAndRefreshWebApplicationContext
的处理基本上一致。
也就是说,当容器启动(如 Tomcat、Jetty、Undertow 等)时,Spring 框架会自动进行初始化。
4.2. ContextLoaderListener.closeWebApplicationContext
ContextLoaderListener.closeWebApplicationContext
public class ContextLoader {
public void closeWebApplicationContext(ServletContext servletContext) {
try {
if (this.context instanceof ConfigurableWebApplicationContext) {
// 调用上下文对象的close方法
((ConfigurableWebApplicationContext) this.context).close();
}
}
finally {
// ... 代码省略
}
}
}
DispatcherServlet.init
与 ContextLoaderListener.contextInitialized
都会进行应用上下文的初始化,主要过程是:
- 初始化 Web 应用上下文,默认使用
XmlWebApplicationContext
(基于 XML 加载)作为应用上下文,并调用refresh
方法 - 实例化由
globalInitializerClasses
和contextInitializerClasses
定义的类 - 实例化 WebMVC 必要的组件:
MultipartResolver
,LocaleResolver
,ThemeResolver
,HandlerMapping
,HandlerAdapter
,HandlerExceptionResolver
,RequestToViewNameTranslator
,ViewResolver
,FlashMapManager
每个请求都会进入到 DispatcherServlet.service
,其主要过程是:
- 初始化请求对象,以便应用后续处理
- 处理 Multipart 文件上传,获取处理器处理当前请求
- 如果当前请求处理发生异常,进行异常处理
- 进行视图渲染
到这里为止,分析仅仅止于 DispatcherServlet
与 ContextLoaderListener
两个类,下一篇将深入其他类,继续探索。
ConfigurableWebApplicationContext.refresh
刷新上下文ApplicationContext.getBean
从上下文中获取 beanDispatcherServlet.properties
文件中定义的策略处理ContextLoader.properties
文件中定义的策略处理View.render
视图渲染
更多博客,查看 https://github.com/senntyou/blogs
版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK