研究源码前,先找到入库类,再根据入口方法一步一步跟踪深入。SpringMvc的入口类为配置在web.xml中继承了servlet的DispatcherServlet
,以下是他的继承关系:
先看这个特殊的servlet的init方法,封装在了HttpServletBean
:
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// 获取配置在web.xml中的自定义参数,并封装到内部类ServletConfigPropertyValues中
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
//在spring boot项目中由于没有配置初始化参数,所以不会执行里面的代码
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;
}
}
//该类中是个空方法,但是在FrameworkServlet该方法已经被重写,用于做一些容器话的操作,比如设置webApplication,设置父容器等
// Let subclasses do whatever initialization they like.
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
来看下FrameworkServlet
重写的initServletBean()
做了什么:
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
//初始化webApplicationContext容器
this.webApplicationContext = initWebApplicationContext();
//又是一个空方法,没有做任何实现
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}
该代码主要用来初始化webApplicationContext容器,webApplicationContext是一个继承于ApplicationContext的ioc上下文容器。类FrameworkServlet
主要作用就是把Spring与servler相关联。
真正创建WebApplicationCont容器的方法:
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// 使用DispatcherServlet的有个带参的WebApplicationContext 的构造方法,当使用该构造方式实例化的时候,会执行该代码
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
//没被初始化过的话(没调用过refreshed方法),设置父容器
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
//以setContextAttribute的方式将ServletContext设置进来
wac = findWebApplicationContext();
}
if (wac == null) {
//反射方式创建一个默认的,XmlWebApplicationContext类型
//设置环境environment,父容器,本地资源文件
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
//调用ioc容器的onRefresh方法,准备做ioc容器的初始化动作
//该方法是个空方法,在DispatcherServlet中被重写
//最后执行容器的refresh方法
onRefresh(wac);
}
//将容器设置到servletContext上下文中
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
当WebApplicationContext
被创建后(同时关联上父容器),接下来调用IOC容器的onRefresh方法,该方法在FrameworkServlet是个空方法,但是在DispatcherServlet中重写了,onRefresh才是真正初始化SpringMvc的入口方法:
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
//解析请求
initMultipartResolver(context);
//多语言环境,国际化
initLocaleResolver(context);
//主题
initThemeResolver(context);
//解析url和methdo的关系,存于requestMap实体类中
initHandlerMappings(context);
//适配器的匹配
initHandlerAdapters(context);
//异常处理器
initHandlerExceptionResolvers(context);
//视图转发
initRequestToViewNameTranslator(context);
//解析模板中的类容,生成html代码
initViewResolvers(context);
//映射管理器
initFlashMapManager(context);
}
onRefresh
方法直接调用了initStrategies
方法,里面做了一些初始化操作。下面将讲解在DispatcherServlet
中一些重要组件的初始化。
initServletBean
模板方法供FrameworkServlet
实现,从而引出后续操作。onRefresh
模板方法供DispatcherServlet
实现,为其初始化SpringMvc组件提供入口。##5、HandlerMapping初始化
private void initHandlerMappings(ApplicationContext context) {
//一个list集合
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// 获取所有注册到容器中的handlerMapping
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 {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// 如果没从容器中获取到的化,默认俩个默认的handlerMappering
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
在初始化HandlerMapping的时候,如果发现用户没有设置任何handlerMapping,则会读取本地org.springframework.web.servlet.DispatcherServlet.properties
文件中的配置项:
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
创建俩个默认:
BeanNameUrlHandlerMapping
RequestMappingHandlerMapping
private void initHandlerAdapters(ApplicationContext context) {
//同样,也是list集合
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
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 {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
}
}
}
用户请求服务器时,进入DispatcherServlet的doService
方法,该方法最终调用了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 {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查是否是文件上传
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 关键代码,找到该请求对应的handler
mappedHandler = getHandler(processedRequest);
//找不到对应的handler,报404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 找到对应的handlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 获取请求结果,封装到modelAndView中了
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
//
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
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);
}
}
}
}
接下来是getHander方法找到请求对应的handler:
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//从initHandlerMappings初始化产生的list中寻找合适的hanlder
if (this.handlerMappings != null) {
for (HandlerMapping hm : this.handlerMappings) {
//匹配handler,最终跳转到了AbstractHandlerMapping的getHandler
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
继续getHandlerAdapter方法
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter ha : this.handlerAdapters) {
//查看该handleradapter是否支持该handler
if (ha.supports(handler)) {
return ha;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
上面代码中ha.supports(handler)
,该方法是判断该adapter是否适配handler,这就是springMvc里面经典的适配器模式了。不同的handlerAdapter方法适配规则不一样。但是都很简单,以HttpRequestHandlerAdapter
为例:
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}