SpringMVC-处理http请求的中间桥梁HandlerAdapter

本文基于spring 5.5.2.release

前面几篇文章介绍了接口HandlerMapping,了解到该接口的作用是根据请求参数查找Handler,这个Handler并没有具体的要求,可以是一个普通的bean对象,也可以是HandlerMethod对象。这就导致DispatcherServlet不能对Handler按照统一的规则处理,因此springmvc提供了适配器HandlerAdapter,将Handler交给适配器处理,适配器对外提供统一接口,DispatcherServlet调用适配器即可。
springmvc对每种Handler都提供了对应的适配器,如果springmvc提供的适配器不符合要求,我们还可以添加自定义适配器。

文章目录

一、HandlerAdapter接口定义

下面看一下HandlerAdapter接口需要实现的方法:

public interface HandlerAdapter {
	/**
	* 检查当前HandlerAdapter实现类是否可以处理Handler
	*/
	boolean supports(Object handler);
	/**
	* 处理http请求的核心方法,
	* 该方法里面会根据Handler对象找到Controller,然后调用Controller处理请求
	*/
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	/**
	* 返回请求内容的最后修改时间,返回值会被放入到响应报文头的Last-Modified字段中,
	* 调用下面这个方法需要Handler实现LastModified接口,springmvc没有提供LastModified的实现类,需要自定义,
	*/
	long getLastModified(HttpServletRequest request, Object handler);
}

二、HandlerAdapter的使用

在这一小节看一下DispatcherServlet如何使用HandlerAdapter。
springmvc接收到的请求都会被转发到DispatcherServlet.doDispatch()方法,下面我们看一下这个方法。

//入参request表示http请求对象,response是响应对象
//下面方法内容有删减
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		try {
			// Determine handler for the current request.
			//在getHandler中遍历HandlerMapping实现类,找到合适的Handler
			//该方法的返回值是HandlerExecutionChain对象,它对Handler做了封装
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			//遍历HandlerAdapter实现类,找到可以处理Handler的适配器
			//在getHandlerAdapter方法里面调用了适配器的supports方法
			//getHandlerAdapter方法内容见下方
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			// Process last-modified header, if supported by the handler.
			String method = request.getMethod();
			boolean isGet = "GET".equals(method);
			if (isGet || "HEAD".equals(method)) {
				//调用HandlerAdapter的getLastModified方法,找到请求内容的最后修改时间
				//该方法要求Handler实现LastModified接口,如果没有实现,该方法可以直接返回-1
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
				//checkNotModified方法将request中的If-Unmodified-Since字段时间与最后修改时间lastModified做比较,
				//如果前者大,那么意味着没有修改过,那么设置报文头Last-Modified字段和状态码,不再进行后续处理,直接向客户端返回响应内容,
				//如果后者大,那么表示修改过,需要调用Controller进行处理。
				//如果入参lastModified小于0,checkNotModified方法认为修改过
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}
			//调用拦截器
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			// Actually invoke the handler.
			//调用Controller或者说是Handler处理请求
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
			//如果mv没有设置view属性值,那么设置默认值
			applyDefaultViewName(processedRequest, mv);
			//调用拦截器
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
	}
}
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	if (this.handlerAdapters != null) {
		//遍历适配器,找到可以处理Handler的适配器
		for (HandlerAdapter adapter : this.handlerAdapters) {
			if (adapter.supports(handler)) {
				return adapter;
			}
		}
	}
	//找不到适配器,直接抛出异常
	throw new ServletException("No adapter for handler [" + handler +
			"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

可以看到doDispatch()方法里面调用了HandlerAdapter接口的三个方法:第一次是调用supports方法以找到可以处理Handler的实现类;第二次是调用getLastModified方法查看最后修改时间,第三次是调用handler方法,处理http请求。

三、HandlerAdapter实现类

springmvc提供五个HandlerAdapter的实现类:
SpringMVC-处理http请求的中间桥梁HandlerAdapter
这些类中只有RequestMappingHandlerAdapter逻辑比较复杂,会在其他文章中详细介绍,剩下类的实现逻辑基本类似,比较简单,本文详细看一下SimpleControllerHandlerAdapter的实现源码,其他的类大家自行查看,不在做介绍。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	@Override
	//该适配器,要求handler必须实现Controller接口
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}

	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		//处理请求直接调用handleRequest方法,返回ModelAndView对象
		//DispatcherServlet会解析ModelAndView,找到对应的View对象,并进行渲染
		return ((Controller) handler).handleRequest(request, response);
	}
	
	//如果handler没有实现LastModified接口,直接返回-1
	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}

}

四、总结

HandlerAdapter是沟通Handler与DispatcherServlet之间的桥梁,由于springmvc没有对Handler做强制要求,任何一个普通的bean都可以作为Handler,因此使用HandlerAdapter将Handler之间的不同屏蔽掉,DispatcherServlet使用统一的方式调用Handler处理请求。

上一篇:How to use Datasets and DataLoader in PyTorch for custom text data


下一篇:frida常见算法hook