Spring 源码解析一:SpringMVC 的加载机制
1. spring-framework
蕴含的模块
在解析 SpringMVC
的加载机制之前,先来看看官网 spring-framework
蕴含有哪些模块,各有什么用。
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>
这里有两个入口类:
servlet-class
org.springframework.web.servlet.DispatcherServlet: 指定用来解决对应 URL 申请的类listener-class
org.springframework.web.context.ContextLoaderListener: 设置事件监听器,事件监听程序在建设、批改和删除会话或 servlet 环境时失去告诉
这两个类别离定义在 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
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
再来看看 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
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
这个类的解析基本上就差不多了,但还有几点没有解析:
- FrameworkServlet(L702):
ConfigurableWebApplicationContext.refresh
- DispatcherServlet(L514):
ApplicationContext.getBean
- DispatcherServlet.properties 文件中定义的策略解决
- DispatcherServlet(L1393):
View.render
这几点,咱们前面再来解析。
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 {// ... 代码省略}
}
}
5. 综述
DispatcherServlet.init
与 ContextLoaderListener.contextInitialized
都会进行利用上下文的初始化,次要过程是:
- 初始化 Web 利用上下文,默认应用
XmlWebApplicationContext
(基于 XML 加载)作为利用上下文,并调用refresh
办法 - 实例化由
globalInitializerClasses
和contextInitializerClasses
定义的类 - 实例化 WebMVC 必要的组件:
MultipartResolver
,LocaleResolver
,ThemeResolver
,HandlerMapping
,HandlerAdapter
,HandlerExceptionResolver
,RequestToViewNameTranslator
,ViewResolver
,FlashMapManager
每个申请都会进入到 DispatcherServlet.service
,其次要过程是:
- 初始化申请对象,以便利用后续解决
- 解决 Multipart 文件上传,获取处理器解决以后申请
- 如果以后申请解决产生异样,进行异样解决
- 进行视图渲染
6. 未完
到这里为止,剖析仅仅止于 DispatcherServlet
与 ContextLoaderListener
两个类,下一篇将深刻其余类,持续摸索。
ConfigurableWebApplicationContext.refresh
刷新上下文ApplicationContext.getBean
从上下文中获取 beanDispatcherServlet.properties
文件中定义的策略解决ContextLoader.properties
文件中定义的策略解决View.render
视图渲染
后续
更多博客,查看 https://github.com/senntyou/blogs
作者:深予之 (@senntyou)
版权申明:自在转载 - 非商用 - 非衍生 - 放弃署名(创意共享 3.0 许可证)