适配器模式在SpringMVC中的应用

今天花了好几个小时撸了SpringMVC的部分源码,在此进行分享!

SpringMVC 中的 HandlerAdapter, 就使用了适配器模式;

下面我们通过源码来分析SpringMVC 中的 HandlerAdapter是如何使用适配器模式的:

//前端控制器DispatcherServlet类
public class DispatcherServlet extends FrameworkServlet {
    //DispatcherServlet类中的核心方法doDispatch
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;//将request交给HttpServletRequest
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;
        …………(省略部分代码)
        //通过request可以得到请求对应的控制器,即controller/handler
        mappedHandler = getHandler(processedRequest);
         …………(省略部分代码)
        //根据handler得到对应的适配器 
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        …………(省略部分代码)
        //通过适配器去调用对应controller的方法,并返回ModelAndView
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}

适配器接口HandlerAdapter的源码:

public interface HandlerAdapter {  
	boolean supports(Object handler);
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
	long getLastModified(HttpServletRequest request, Object handler);
}

适配器接口HandlerAdapter的具体实现类,即具体的适配器类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EROwqERX-1586877667287)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200414223017883.png)]

列出其中一个具体的实现类HttpRequestHandlerAdapter的源码,可以看到无非就是重写了接口中的三个方法,其中supports方法就是判断handler是否对应这个适配器实现类,返回一个布尔值;而handle方法就是去调用具体的controller方法,并返回ModelAndView

public class HttpRequestHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
		return (handler instanceof HttpRequestHandler);
	}

	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		((HttpRequestHandler) handler).handleRequest(request, response);
		return null;
	}

	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}
}

对以上源码进行总结,SpringMVC 中的 HandlerAdapter用到适配器模式的流程:

  1. 将request交给HttpServletRequest
  2. 通过request可以得到请求对应的控制器,或者叫处理器;即controller/handler
  3. 根据handler得到对应的适配器
  4. 通过适配器去调用对应controller的方法,并返回ModelAndView(表明看执行的是适配器的handle方法,实际上适配器执行的就是对应controller的方法)

有了适配器模式,最终是通过具体的适配器类来调用controller中的方法,那么为什么不直接去调用controller中的方法,而要通过适配器来调用呢,这不是多此一举吗?

当然不是多此一举,可以看到处理器的类型不同,有多重实现方式,那么调用方式就不是确定的,如果需要直接调用 Controller 方法,需要调用的时候就得不断是使用 if else 来进行判断是哪一种子类然后执行。那么如果后面要扩展 Controller,就得修改原来的代码,这样违背了 OCP 原则。

另外,把每个controller的方法差异封装到各个 HandlerAdapter的实现类里,对外只暴露统一的handle方法。

前面在类适配器模式我们提到,由于适配器类继承了被适配器类的方法,因此在适配器类中我们可以会直接调用被适配器类的方法,这样就使得被适配器类的方法在 Adapter 中会暴露出来,增加了使用的成本;而SpringMVC中的HandlerAdapte使用了适配器模式后就解决了这个问题。

拓展:SpringMVC处理请求流程

流程图:
在这里插入图片描述

具体步骤:

  1. 用户发送请求至前端控制器DispatcherServlet;
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器;
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispathcerServlet;
  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器;
  5. 执行处理器(Controller,也叫后端控制器);
  6. Controller执行完成后返回ModelAndView;
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet;
  8. DispatcherServlet将ModelAndView传给ViewResolver视图解析器;
  9. ViewResolver解析后返回具体View对象;
  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中),或者说视图渲染是将模型数据在ModelAndView对象中填充到request域);
  11. DispathcerServlet响应用户。

补充:之前曾在笔试题中遇到一道关于DispatcherServlet作用的题目,当时答不上来,现在在此作为补充;

附上一篇对DispatcherServlet的作用整理得很详细的博客:

https://www.cnblogs.com/shilin000/p/4759015.html

猜你喜欢

转载自blog.csdn.net/can_chen/article/details/105524137
今日推荐