【Spring】SpringMVC DispatcherServlet 和 Controller的交互

1. MVC架构

在这里插入图片描述

1.1 FrontController: DispatcherServlet

FrontController就是Spring提供的DispatcherServlet , 而不是Spring提供的@Controller,xml配置文件需要指定Tomcat启动时优先加载该Servlet映射路径写/,转发所有请求

 	<servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--tomcat启动的时候, 优先加载这个Servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

DispatcherServlet本质上是一个HttpServlet

在这里插入图片描述

追踪HttpServlet.service() 方法的调用链
  • FrameworkServlet 继承父类的HttpServlet.service,Spring的拓展实现是processRequest

    FrameworkServlet.processRequest,==Spring会拦截所有类型的请求,包括HttpServlet里没有定义的,==继续追踪processRequest的实现

    	@Override
    	protected void service(HttpServletRequest request, HttpServletResponse response) {
    		HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    		if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
    			processRequest(request, response);
    		}
    		else {
    			super.service(request, response);
    		}
    	}
    
  • FrameworkServlet.processRequest组合了doService逻辑

    	protected final void processRequest(HttpServletRequest request, HttpServletResponse response) {
    		try {
    			doService(request, response);
    		}
            // 留作后文研究
    		publishRequestHandledEvent(request, response, startTime, failureCause);
    		}
    	}
    
  • FrameworkServlet的抽象方法doService 是留给子类必须实现的,也就是DispatcherServlet.doService()

    protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
       /**
     	* DispatcherServlet.doService()
    	*
     	*/
    	@Override
    	protected void doService(HttpServletRequest request, HttpServletResponse response) {		
            // 省略数据准备
    		try {
    			doDispatch(request, response);
    		}
    	}
    
追踪FrameworkServlet.doPost() / doGet() …
  • FrameworkServlet.doGet/doPost/..无一例外使用processRequest的实现,也就是DispatcherServlet.doService

在这里插入图片描述

探究FrameworkServlet.service() 模板方法实现
  • super.service()

    利用了模板设计模式,Spring 兼容了PATCH的实现,其他交给HttpServlet的模板service()

    	@Override
    	protected void service(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    		if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
    			processRequest(request, response);
    		}
    		else {
    			super.service(request, response);
    		}
    	}
    
  • HttpServlet.service() 模板,无具体实现。由于FrameworkServlet.doGet/doPost..都已经覆盖了

    HttpServlet的实现,一个Get请求经过DispatcherServlet后,有以下过程

    FrameworkServlet.service() -> super.service() -> FrameworkServlet.doGet()

    -> FrameworkServlet.processRequest() -> DispatcherServlet.doService

    -> DispatcherServlet.doDispatch()

       /**
    	* super.service() 最总会调用到 HttpServlet 的模板方法
    	*
    	*/
    	protected void service(HttpServletRequest req, HttpServletResponse resp) {
            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);
            }
        }
    

小结

DispatcherServlet 作为MVC架构中的前端控制器,也是常说的核心控制器, 通过HttpServlet.service()的模板模式把请求 转发给Spring ,DispatcherServlet.doService() 后续解析,

关于DispatcherServlet的其他父类, 网上收集到的作用:

  1. HttpServletBean,是FrameworkServlet的父类

    主要做一些初始化的工作,将web.xml中配置的参数设置到Servlet中。比如servlet标签的子标签init-param标签中配置的参数。

  2. FrameworkServlet

    将Servlet与Spring容器上下文关联。其实也就是初始化FrameworkServlet的属性webApplicationContext,这个属性代表SpringMVC上下文,它有个父类上下文ServletContext,既web.xml中配置的ContextLoaderListener监听器初始化的容器上下文。

  3. DispatcherServlet (后文会提到)

    初始化各个功能的实现类。比如异常处理、视图处理、请求映射处理等。
    在这里插入图片描述

2. MVC交互流程

在这里插入图片描述

2.1 Controller: DispatcherServlet.doService()

追踪 DispatcherServlet.doDispatch()

doService() 内部调用的是 doDispatch()

	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
    	HttpServletRequest processedRequest = request;
        // Determine handler for the current request.(追踪)
		HandlerExecutionChain mappedHandler = getHandler(processedRequest)
		// Determine handler adapter for the current request.(追踪)
		HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

		// Actually invoke the handler.(追踪)
		mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
		applyDefaultViewName(processedRequest, mv);
		mappedHandler.applyPostHandle(processedRequest, response, mv);	
	}
追踪 DispatcherServlet.getHandler()
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		for (HandlerMapping hm : this.handlerMappings) {
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}

Handler 是根据 HandlerMapping 获取的,对应Controller的@RequestMapping

追踪 DispatcherServlet. getHandlerAdapter()
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (ha.supports(handler)) {
				return ha;
			}
		}
	}
追踪 HandlerAdapter.handle()
ModelAndView handle(HttpServletRequest request, HttpServletResponse response,
                    Object handler) throws Exception;

在DispatcherServlet中找到ModelAndView 的返回值出处

追踪 HandlerAdapter 实现类 SimpleControllerHandlerAdapter
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return ((Controller) handler).handleRequest(request, response);
	}
追踪 Controller 实现
public interface Controller {
	@Nullable
	ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;

}

最终找到了 Controller 返回MV的代码, 也印证了DispatcherServlet.doDispatcher 最终会返回 Controller 拼装而成的 ModelAndView

2.2 Model And View

不同的视图解析器决定如何处理解析 视图名,所以SpringMVC需要配置视图解析器

public interface ViewResolver {
	@Nullable
	View resolveViewName(String viewName, Locale locale) throws Exception;
}

3. 总结

DispatcherServlet 会寻找 HandlerMapping 和 HandlerMapping , 解析视图的时候会用到 ViewResolver

如果手动集成SSM,SpringMVC需要手动注入这三个bean。值得一提的是,XML配置如果开启了注解支持,HandlerMapping 和 HandlerMapping 也随之加载。具体可以见以下图

在这里插入图片描述

©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页