SpringMVC中的HandlerMapping和HandlerAdapter

HandlerMapping

处理器映射。看下官方文档中的解释:

由定义请求和处理程序对象之间的映射的对象实现的接口。
这个类可以由应用程序开发人员实现,尽管这不是必需的,因为 org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping 和 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 都包含在框架中。如果在应用程序上下文中没有注册 HandlerMapping bean,则前者是默认值。
HandlerMapping 实现可以支持映射拦截器,但不是必须的。处理程序将始终包装在 HandlerExecutionChain 实例中,可选地伴随一些 HandlerInterceptor 实例。 DispatcherServlet 将首先按给定顺序调用每个 HandlerInterceptor 的 preHandle 方法,如果所有 preHandle 方法都返回 true,则最后调用处理程序本身。
参数化这个映射的能力是这个 MVC 框架的一个强大而不同寻常的能力。例如,可以根据会话状态、cookie 状态或许多其他变量编写自定义映射。似乎没有其他 MVC 框架具有同样的灵活性。
注意:实现可以实现 org.springframework.core.Ordered 接口,以便能够指定排序顺序,从而指定 DispatcherServlet 应用的优先级。无序实例被视为最低优先级。

作用:

  • 1、让HandlerMapping找到处理当前请求的对象,这个对象叫做handler;
  • 2、HandlerMapping是可以有顺序的进行选择(实现Ordered接口)

在当期接口中,有一个重要方法:

public interface HandlerMapping {
  // 根据当前请求找到能够处理的HandlerExecutionChain
  HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

HandlerExecutionChain

而在HandlerExecutionChain类中,可以看到当前类中的重点:

public class HandlerExecutionChain {
	..........
      
	private final Object handler;

	private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
   
  	......
}

HandlerExecutionChain是由handler(处理器)和interceptorList(拦截器集合)。

handler

在Spring MVC中,任何可以用于Web请求处理的处理对象统称为Handler。Controller是Handler的一种特殊类型。

HandlerMapping通过HandlerExecutionChain所返回的是一个Object类型的Handler对象,而并没限定说只能是Controller类型。

所以,一般意义上讲,任何类型的Handler都可以在Spring MVC中使用,比如Struts的Action和WebWork的Action等,只要它们是用于处理Web请求的处理对象就行。

不过,对于DispatcherServlet来说,这就有点儿问题了,它如何来判断我们到底使用的是什么类型的Handler,又如何决定调用Handler对象的哪个方法来处理Web请求呢?

显然,在DispatcherServlet直接硬编码if-else来枚举每一种可能的Handler类型是不具任何扩展性的。

为了能够以统一的方式调用各种类型的Handler,DispatcherServlet将不同Handler的调用职责转交给了一个称为HandlerAdaptor的角色。

HandlerAdapter

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

HandlerAdaptor将作为一个适配器,屏蔽不同Handler类型给DispatcherServlet)所造成的“困扰”**。这也是适配器模式存在的意义。

HandlerAdapter得以成为DispatcherServlet和不同Handler的“中间人”,要归功于它的两个主要方法,即supports(…)和handle(…)。

至于getLastModified(…)方法,它的主要目的只是为返回给客户端的Last-Modified这个HTTP头提供相应的时间值。如果我们不想支持该功能,直接返间-1即可。

DispatcherServlet从HandlerMapping获得一个Handler之后,将询问HandlerAdaptor的supports(…)方法,以便了解当前HandlerAdaptor是否支持HandlerMapping刚刚返回的Handler类型的调用

                ....
                // 获取得到handler
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
                ....
				//寻找上面返回的handler对应的HandlerAdapter 
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

如果supports(…)返回true,DispatcherServlet则调用HandlerAdaptor的Handle方法,同时将刚才的Handler作为参数传入。

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  if (this.handlerAdapters != null) {
    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");
}

方法执行后将返回ModelAndview,之后的工作就由ViewResolver接手了。

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				//通过HandlerAdapter的handle方法返回一个ModelAndView
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

DispatcherServlet和HandlerAdaptor的关系

DispatcherServlet只需要面对HandlerAdaptor提供的统一接口,而不需要面对纷繁复杂的Handler类型。支持新的Handler类型,意味着只需要为DispatcherServlet提供新的HandlerAdaptor实现即可。

DispatcherServlet借助多个HandlerAdaptor,调用当前HandlerMapping所返回的Handler:来处理Web请求的逻辑。

所以无论我们想在Spring MVC中使用什么类型的Handler,只要同时为DispatcherServlet:提供对应该Handler的HandlerAdaptor实现就行,DispatcherServlet无须任何变动。

我想,HandlerAdaptor存在的原因我们已经搞清楚了,但还有一些问题不明,比如:

  • 1、如果Controller只是一种特殊类型的Handler,那么Spring MVC是否还提供了其他可用的Handler类型呢?如果要提供我们自己的Handler类型又需要考虑哪些事情呢?
  • 2、如何实现一个具体的HandlerAdaptor? Spring MVC有提供现成的实现吗?
  • 3、如果想使用自定义的Handler,并且提供了对应的HandlerAdaptor实现,要通过什么方式告知DispatcherServlet来使用它们?

我想只有解开以上问题的答案才能帮助我们更深刻地理解Handler与HandlerAdaptor之间的关系。

深入了解Handler

到目前为止,我们使用最多的Handler就是Controller。不过,如果Controller不合我们的口味的话,我们也可以使用Spring MVC提供的其他类型的Handler,甚至于自定义Handler类型。

可以说,自定义Handler对于Handler类型来说并没任何限制,任何我们喜欢的形式都可以。如果不喜欢Controller,那么可以定义自己的MyHandler,甚至不需要强制Handler实现任何接口,仅是一个简单的POJO对象,只要能有办法知道该类就是用于Web请求处理的Handler类就行,比如用注解标注一下,然后通过反射机制就能获知哪些对象是用于Web请求处理的Handler,如下所示:

@Handler
public class AnyType{}

虽说对Handler自身没有任何限制,但是要让我们的Handler登上“历史舞台”发挥它的作用,却需要有能够给予帮助的“左膀右臂”,为我们的Handler提供必要的HandlerMappingHandlerAdaptor,这才是真正让Handler自身没有任何限制的原因所在。

HandlerMapping负责查找相应的Handler以处理Web请求

	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

可以看到每种HandlerMapping得到的handler是不同的。

看下org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler中的实现过程:

这里就是为了满足各种各样的handlermapping映射的handler的。

要想使用Handler,首先需要提供一个能够识别该Handler的HandlerMapping实现。比如,无论是BeanNameUrlHandlerMapping还是SimpleUrlHandlerMapping,它们都可以获取并返回Controller类型的Handler.。

如果可以通过BeanNameUrlHandlerMapping或者SimpleUrlHandlerMapping告知DispatcherServlet我们的Handler存在的话,那还好。否则,我们就不得不提供一个能够识别我们自己Handler类型的HandlerMapping。

现在HandlerMapping返回了我们自定义的Handler,但DispatcherServlet本身显然是不管我们的Handlerl到底是何方人物的。为了让我们的Handler得以被DispatcherServlet所“青睐”,我们不得不提供一个HandlerAdaptor。实际上,并非只有我们的自定义Handler要“受此礼遇”,所有SpringMVC框架内的Handler都提供有相对应的HandlerAdaptor实现,如下所述:

  • Controller 将 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter作为其HandlerAdaptor。
  • Spring2.5新添加的基于注解的Handler由org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter作为其HandlerAdaptor。

深入理解HandlerAdapter

可以直接去看下当前spring版本中的HandlerAdapter中的实现类

即可进去看一下根据HandlerAdapter找到的handler是如何来进行处理的。

主要工作只是调用这个HandlerAdaptor“认识”的Handler的Web请求处理方法,然后将处理结果转换为DispatcherServlet统一使用的ModelAndview就行。

SimpleServletHandlerAdapter

直接利用service来进行处理

public class SimpleServletHandlerAdapter implements HandlerAdapter {
	
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Servlet);
	}

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

		((Servlet) handler).service(request, response);
		return null;
	}

	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		return -1;
	}

}

SimpleControllerHandlerAdapter

实现了controller接口的类来进行处理

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

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

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

		return ((Controller) handler).handleRequest(request, response);
	}

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

}

HttpRequestHandlerAdapter

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;
	}

}

AbstractHandlerMethodAdapter

处理的handler是HandlerMethod类型的

public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {

	private int order = Ordered.LOWEST_PRECEDENCE;


	public AbstractHandlerMethodAdapter() {
		// no restriction of HTTP methods by default
		super(false);
	}

	public void setOrder(int order) {
		this.order = order;
	}

	@Override
	public int getOrder() {
		return this.order;
	}

	@Override
	public final boolean supports(Object handler) {
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}

	/**
	 * Given a handler method, return whether or not this adapter can support it.
	 * @param handlerMethod the handler method to check
	 * @return whether or not this adapter can adapt the given method
	 */
	protected abstract boolean supportsInternal(HandlerMethod handlerMethod);

	/**
	 * This implementation expects the handler to be an {@link HandlerMethod}.
	 */
	@Override
	@Nullable
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}

	/**
	 * Use the given handler method to handle the request.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handlerMethod handler method to use. This object must have previously been passed to the
	 * {@link #supportsInternal(HandlerMethod)} this interface, which must have returned {@code true}.
	 * @return a ModelAndView object with the name of the view and the required model data,
	 * or {@code null} if the request has been handled directly
	 * @throws Exception in case of errors
	 */
	@Nullable
	protected abstract ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;

	/**
	 * This implementation expects the handler to be an {@link HandlerMethod}.
	 */
	@Override
	public final long getLastModified(HttpServletRequest request, Object handler) {
		return getLastModifiedInternal(request, (HandlerMethod) handler);
	}

	/**
	 * Same contract as for {@link javax.servlet.http.HttpServlet#getLastModified(HttpServletRequest)}.
	 * @param request current HTTP request
	 * @param handlerMethod handler method to use
	 * @return the lastModified value for the given handler
	 */
	protected abstract long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod);

}

源码总结加载HandlerAdaptor

首先来到org.springframework.web.servlet.HttpServletBean#init,因为HttpServletBean实现了HttpServlet接口,所以在Tomcat服务器在启动的时候执行这个方法

		// Let subclasses do whatever initialization they like.
		initServletBean();

在org.springframework.web.servlet.FrameworkServlet#initServletBean方法中会调用:

this.webApplicationContext = initWebApplicationContext();

来进行处理初始化容器之外,还会调用org.springframework.web.servlet.FrameworkServlet#onRefresh

看一下实现:

	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

具体的实现过程:

	/**
	 * Initialize the strategy objects that this servlet uses.
	 * <p>May be overridden in subclasses in order to initialize further strategy objects.
	 */
	protected void initStrategies(ApplicationContext context) {
        // 初始化文件解析器
		initMultipartResolver(context);
		initLocaleResolver(context);
        //解析器
		initThemeResolver(context);
        // 初始化重点HandlerMapping和HandlerAdapter
		initHandlerMappings(context);
		initHandlerAdapters(context);
        // 初始化异常解析器
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
        // 初始化视图解析器
		initViewResolvers(context);
		initFlashMapManager(context);
	}

初始化HandlerMapping

	// 如果没有找到HandlerMapping类型的bean,这里默认使用BeanNameUrlHandlerMapping
	/**
	 * Initialize the HandlerMappings used by this class.
	 * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
	 * we default to BeanNameUrlHandlerMapping.
	 */
private void initHandlerMappings(ApplicationContext context) {
  this.handlerMappings = null;

  // 默认为true,表示检查所有HandlerMapping的bean
  if (this.detectAllHandlerMappings) {
    // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
    Map<String, HandlerMapping> matchingBeans =
      BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
    if (!matchingBeans.isEmpty()) {
      this.handlerMappings = new ArrayList<>(matchingBeans.values());
      // 开始根据sort接口来进行排序
      // We keep HandlerMappings in sorted order.
      AnnotationAwareOrderComparator.sort(this.handlerMappings);
    }
  }
  else {
    try {
      HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
      this.handlerMappings = Collections.singletonList(hm);
    }
    catch (NoSuchBeanDefinitionException ex) {
      // Ignore, we'll add a default HandlerMapping later.
    }
  }
  // 如果为空,那么就根据默认策略是寻找springmvc自带的
  // Ensure we have at least one HandlerMapping, by registering
  // a default HandlerMapping if no other mappings are found.
  if (this.handlerMappings == null) {
    this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
    if (logger.isTraceEnabled()) {
      logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                   "': using default strategies from DispatcherServlet.properties");
    }
  }

  for (HandlerMapping mapping : this.handlerMappings) {
    if (mapping.usesPathPatterns()) {
      this.parseRequestPath = true;
      break;
    }
  }
}

看下具体的实施措施:

这里传进来的参数是HandlerMapping类型的

	protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		if (defaultStrategies == null) {
			try {
				// Load default strategy implementations from properties file.
				// This is currently strictly internal and not meant to be customized
				// by application developers.
				ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
				defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
			}
			catch (IOException ex) {
				throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
			}
		}

		String key = strategyInterface.getName();
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
            // 又遇到了,按照,进行分割
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<>(classNames.length);
			for (String className : classNames) {
				try {
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
				}
				catch (ClassNotFoundException ex) {
					throw new BeanInitializationException(
							"Could not find DispatcherServlet's default strategy class [" + className +
							"] for interface [" + key + "]", ex);
				}
				catch (LinkageError err) {
					throw new BeanInitializationException(
							"Unresolvable class definition for DispatcherServlet's default strategy class [" +
							className + "] for interface [" + key + "]", err);
				}
			}
			return strategies;
		}
		else {
			return Collections.emptyList();
		}
	}

对应的在springmvc依赖下面的

所以默认会有三种来进行加载进来。

也就是说,如果使用的Handler是现有Handler类型,那么无须在DispatcherServlet的WebApplicationContext中做任何配置,默认的HandlerAdaptor已经足够了。不过,如果需要添加这些HandlerAdaptor类型之外的HandlerAdaptor实现,并且我们依然希望同时使用这些默认HandlerAdaptor所支持的Handler的话,那就需要在添加我们的自定义HandlerAdaptor的基础上,同时添加以上几种默认的HandlerAdaptor实现。

总结加载HandlerAdapter

和上面是一样的套路。

总结

1、首先加载得到HandlerMapping和HandlerAdapter类型的bean;

2、当请求来临的时候,调用HandlerMapping找到对应的handler;

3、通过HandlerAdapter调用对应的handler返回响应结果值;

文档参考:https://cjdhy.blog.csdn.net/article/details/126137179

posted @ 2022-09-28 17:00  雩娄的木子  阅读(402)  评论(0编辑  收藏  举报