自学内容网 自学内容网

【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对异常进行包装处理和返回


原文地址:https://blog.csdn.net/weixin_44541808/article/details/143880377

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!