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的实现类:
在这里插入图片描述
这些类中只有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

如果当前提供的HandlerAdapter对象不符合要求,我们可以自定义HandlerAdapter实现类。那么springmvc如何找到自定义的类呢?
在上面的代码getHandlerAdapter()方法中,可以看到DispatcherServlet遍历了属性handlerAdapters来找到合适的HandlerAdapter对象,那么只要自定义的HandlerAdapter对象能够加入到属性handlerAdapters中即可,那么下面来看一下handlerAdapters如何初始化的。
在初始化时,springmvc会调用initHandlerAdapters来初始化属性handlerAdapters:

	private void initHandlerAdapters(ApplicationContext context) {
		this.handlerAdapters = null;
		//detectAllHandlerAdapters默认是true
		if (this.detectAllHandlerAdapters) {
			//从容器以及父容器中找到所有的HandlerAdapter对象
			Map<String, HandlerAdapter> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerAdapters = new ArrayList<>(matchingBeans.values());
				// We keep HandlerAdapters in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerAdapters);
			}
		}
		else {
			try {
				//通过bean名字找到HandlerAdapter对象
				HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
				this.handlerAdapters = Collections.singletonList(ha);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerAdapter later.
			}
		}
		//如果容器中没有HandlerAdapter对象,那么使用默认的
		if (this.handlerAdapters == null) {
			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

根据initHandlerAdapters()方法可以知道只要自定义的HandlerAdapter对象放入到spring容器中,springmvc就可以找到该对象,并将其加入到属性handlerAdapters中。

五、总结

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值