【SpringMVC原理分析】
Spring MVC大家应该都很熟悉吧。作为一个全面的Web框架,提供了构建Web应用程序所需的所有基础设施。下面我们结合源码从两个方面来分析, SpringMVC到底是怎么工作的。
- Spring MVC 基础设施准备过程
- Spring MVC 的工作流程
1、Spring MVC 基础设施准备过程
tomcat启动的时候会执行Servlet的init方法, 所以准备流程肯定是在这个方法中。
public interface Servlet {
//启动入口
void init(ServletConfig var1) throws ServletException;
}
//实现了Servlet接口
public abstract class HttpServletBean...{
//执行init方法
public final void init() throws ServletException {
...
// 执行初始化
initServletBean();
}
}
追踪源码进入到initServletBean()方法, 这个方法会初始化spring容器, 并完成容器的刷新动作。
关键在刷新容器之前注册了一个ContextRefreshListener用来监听容器的刷新动作。
那势必会在监听方法中做一些事情。
public interface Servlet {
//启动入口
void init(ServletConfig var1) throws ServletException;
}
//实现了Servlet接口
public abstract class HttpServletBean...{
//执行init方法
public final void init() throws ServletException {
...
// 执行初始化
initServletBean();
}
}
public abstract class FrameworkServlet ...{
@Override
protected final void initServletBean() throws ServletException {
try {
//初始化spring容器
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
}
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
...
if (wac == null) {
//创建spring容器
wac = createWebApplicationContext(rootContext);
}
...
}
protected WebApplicationContext createWebApplicationContext(...) {
...
//刷新容器
configureAndRefreshWebApplicationContext(wac);
return wac;
}
protected void configureAndRefreshWebApplicationContext(...) {
...
//注册监听器
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
...
applyInitializers(wac);
//在这里刷新
wac.refresh();
}
}
我们找到这个监听器, 发现监听的是ContextRefreshedEvent事件。
也就是说这时候spring中的bean都已经初始化好了。
在这个事件的处理中初始化了HandlerMappings和HandlerAdapters。
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
FrameworkServlet.this.onApplicationEvent(event);
}
}
//最后追踪到DispatcherServlet类的initStrategies方法
public class DispatcherServlet extends FrameworkServlet {
@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);
initFlashMapManager(context);
}
}
追踪到这里基本思路已经很清晰了, 剩下就是代码实现细节。
下面简单介绍下initHandlerMappings和initHandlerAdapters在这两个方法主要干了啥事。
- initHandlerMappings
主要注册了三个默认的Mapping Bean, 分别对应处理三种方式实现的servlet :
1、BeanNameUrlHandlerMapping处理实现了controller或者HttpRequestHandler接口的Servlet。
2、RequestMappingHandlerMapping处理被@Controller或者@RequestMapping注解标注的Servlet。
3、RouterFunctionMapping处理HandlerFunction类型的Bean。 - initHandlerAdapters
主要是注册四个默认的适配器, 以便请求过来的时候去执行不同的handlerMethod, 当然这个过程还包含参数处理,返回值处理等都会初始化相应的处理对象封装到适配器中:
1、如果是@Controller -> RequestMappingHandlerAdapter。
2、如果是HttpRequestHandler接口 -> HttpRequestHandlerAdapter。
3、如果是Controller接口 -> SimpleControllerHandlerAdapter。
4、如果是HandlerFunction对象 -> HandlerFunctionAdapter。
至此, springmvc的基础设施基本就准备好了。
2、Spring MVC 工作流程
那Spring MVC 是如何工作的呢?
如何将一个Request请求路由到我们的Controller, 又是如何调用方法的, 参数和返回值又是怎么处理的呢?
下面看源码分析下:
public interface Servlet {
//入口自然是service方法
void service(ServletRequest var1, ServletResponse var2);
}
public class DispatcherServlet extends FrameworkServlet {
protected void doService(HttpServletRequest request, HttpServletResponse response){
...
doDispatch(request, response);
...
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response){
...
// 根据path找到对应的HandlerExecutionChain(包含HandlerMethod与HandlerInterceptor)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
//404
noHandlerFound(processedRequest, response);
return;
}
// 根据HandlerMethod找到匹配的Adapter
// 如果是@Controller -> RequestMappingHandlerAdapter
// 如果是HttpRequestHandler接口 -> HttpRequestHandlerAdapter
// 如果是Controller接口 -> SimpleControllerHandlerAdapter
// 如果是HandlerFunction对象 -> HandlerFunctionAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
// 调用HandlerInteceptor的applyPreHandler方法 如果返回false 结束调用流程
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 调用handler方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 设置默认视图
applyDefaultViewName(processedRequest, mv);
// 调用HandlerInteceptor的applyPostandler方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
//渲染视图
processDispatchResult(...);
...
}
}
从上面源码, 我们从Servlet的service方法一直追踪到DispatcherServlet的doDispatcher方法, 看到了对request的处理流程:
1、先通过HandlerMapping拿到request对应的HandlerExcutionChain, 并且根据HandlerExcutionChain中的handler找到对应的Adapter。
2、执行HandlerExcutionChain中的interceptor的preHandle方法(责任链模式), 这个过程中只要有一个拦截器返回false就不再往后执行, 直接执行afterCompletion方法然后return。
3、然后就是执行handler方法, 其中包括用HandlerMethodArgumentResolver解析参数, 并且在执行完方法后用HandlerMethodReturnValHandler对返回值进行解析处理(适配器模式&组合模式&策略模式)
4、方法执行完后, 执行HandlerExcutionChain中的interceptor的postHandle方法进行后置处理
5、处理完后得到执行结果ModelAndView, 还需要进行render, 把ModelAndView的view渲染到response中
6、另外如果发生异常, 还会进行异常处理, 这时候就要用到HandlerExceptionResolver对异常进行包装处理和返回