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提供必要的HandlerMapping和HandlerAdaptor,这才是真正让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返回响应结果值;