备注360第三天
说到springmvc源码 肯定是要从DispatcherServlet说起,说到Servlet复习一下其中的方法
public interface Servlet {
/**
* servlet容器只调用一次init方法,在实例化servlet之后。初始化方法必须成功完成后,servlet才
能接收任何请求。
* @param config 容器的配置和初始化参数
*/
public void init(ServletConfig config) throws ServletException;
/**
返回一个包含初始化和启动参数的对象。 这个返回的对象是传递给init的参数对象
* @see #init
*/
public ServletConfig getServletConfig();
/**
* 这个方法是等init完成后才可以被执行的,处理请求和相应
**/
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
/**
*返回有关servlet的信息,例如作者、版本和版权所有。
*/
public String getServletInfo();
/**
* 由servlet容器调用,以向servlet指示正在停止使用。此方法只调用一次,servlet的服务方法中的线程已退出或超时时间过后。在servlet容器调用方法,它将不会在此上再次调用服务方法servlet。
*/
public void destroy();
}
其中在DispatchServlet中,初始化(init)时,就初始化了各个策略
HttpServletBean的init()方法
@Override
public final void init() throws ServletException {
...
// 让子类实现初始化逻辑.
initServletBean();
}
FrameworkServlet的初始化逻辑
@Override
protected final void initServletBean() throws ServletException {
...
// 初始化web应用上下文
this.webApplicationContext = initWebApplicationContext();
...
}
protected WebApplicationContext initWebApplicationContext() {
...
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) {
//手动刷新上下文
onRefresh(wac);
}
}
...
return wac;
}
重点来到DispatcherServlet中,开始初始化策略
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
//初始化各个策略
protected void initStrategies(ApplicationContext context) {
// 初始化上传解析器
initMultipartResolver(context);
//初始化语言解析器
initLocaleResolver(context);
//初始化主题解析器
initThemeResolver(context);
//初始化处理映射器
initHandlerMappings(context);
//初始化处理适配器
initHandlerAdapters(context);
//初始化异常解析器
initHandlerExceptionResolvers(context);
//初始化请求到的视图名称翻译器
initRequestToViewNameTranslator(context);
//初始化视图解析器
initViewResolvers(context);
//初始化flash映射管理器
initFlashMapManager(context);
}
这里主要看初始映射器和适配器
spring系列最讲究拓展性,这里我思考HanderMapping应该可以存在自定义的情况,接下来debug去查看initHandlerMappings
private void initHandlerMappings(ApplicationContext context) {
...
//看到这里应该存在自定义的点。
为什么这么说,拓展点目前看来分两种,
1、通过先定义接口,之后再通过加载对应实现类的方式拓展的
2、通过类似观察者模式这种去拓展
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
...
}
//BeanFactoryUtils类
public static <T> Map<String, T> beansOfTypeIncludingAncestors(
ListableBeanFactory lbf, Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
Map<String, T> result = new LinkedHashMap<>(4);
//加载HandlerMapping接口的所有类
result.putAll(lbf.getBeansOfType(type, includeNonSingletons, allowEagerInit));
...
return result;
}
//AbstractApplicationContext
@Override
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBeansOfType(type);
}
后续就是遍历查找对应类型的类了,查找出来放进去,目前默认的有
后续再一一查看上述各个类的功能
接下来 initHandlerAdapters 也是一样的套路
以上是相当于走完 servlet的init方法
接下来是service方法 也就是请求和相应的过程
首先来看DispatcherServlet的doDispatch方法,也就是整体mvc的请求流程
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
//检查上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//获取请求对应的映射器,其中包含处理类的信息、拦截器信息等
mappedHandler = getHandler(processedRequest);
//没有找到就直接返回了
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
//通过映射器找到对应适配器,这里为什么还需要适配器去处理呢,为什么不通过
映射器直接去处理呢?
这里是因为controller有多种实现方式
1、通过@Controller注解方式
2、通过继承Controller等
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
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;
}
// 真正的通过反射去调用对应的处理方法,并返回视图解析器,如果返回的是字符串,则返回null
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) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//处理结果
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);
}
}
}
}
小结:
首先是通过Servlet的init方法,进行准备阶段(各种解析器)
接下来请求流程:
- DispatcherServlet的service方法进入流程
- 先找到处理类的处理映射器,返回带有拦截器、处理类信息等的处理执行链
- 通过返回的处理执行链这个类去匹配对应适配器
- 执行拦截器链前置处理
- 通过适配器通过反射去执行对应的处理方法,并返回视图解析器
- 执行拦截器的后置处理
- 通过视图解析器找到对应视图返回给用户