SpringMVC中的HandlerAdapter
还记得在DispatcherServlet中SpringMVC处理请求的逻辑吗,网上有一个非常棒的图,阐明了请求分发处理的整个过程。
映射处理器HandlerMapping根据Request返回一个HandlerExecutionChain实例,HandlerExecutionChain并不是真正的处理器Handler,而是包含了Handler以及拦截器HandlerInterceptor的封装后的调用链对象。系统中可能存在多个HandlerMapping,不同的HandlerMapping对应着不同的策略。DispatcherServlet根据先后顺序,哪个HandlerMapping最先找到处理器,则使用当前的处理器并且立即停止继续查找。
DispatcherServlet获取到处理器Handler后,它并不知道如何使用这个处理器。因为处理器可能多种多样,没有遵循一种标准,它只是一个Object。所以这里需要多Handler进行适配,使得所有的处理器共同拥有一个标准的接口处理请求。Spring使用的适配器的名字就是HandlerAdapter,看它的定义:
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
supports方法用来判断是否支持当前的处理器,handler方法用来处理请求返回ModelAndView。选取
HandlerAdapter的方式跟HandlerMapping的方式非常相似,只不过一个是根据请求选取处理器,一个是根据处理器选取处理器的适配器。下面是选取HandlerAdapter的方法
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: Does your handler implement a supported interface like Controller?");
}
可以看出,HandlerAdapter需要与HandlerMapping配合使用,如果
HandlerMapping返回的处理器没有对应的适配器是会出现异常的。
HandlerAdapter的初始化
和HandlerMapping一样,HandlerAdapter的初始化也在DispatcherServlet的initStrategies方法中,具体初始化方法如下:
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
OrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
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.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
}
}
}
首先尝试向容器索取HandlerAdapter,索要的方式分为两种:第一种是根据类型获取所有的HandlerAdapter类型的Bean,另一种是根据名字向容器索要名字为“handlerAdapter”的Bean。具体使用哪种方式根据参数detectAllHandlerAdapters决定,默认为true,可以在web.xml中设置。
若容器中没有找到HandlerAdapter,则spring会加载使用默认的HandlerAdapter。其实不仅HandlerAdapter是这样,DispatcherServlet的一些其它组件在某些情况也会使用默认的配置。它们通过一个共同的方法获取:
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<T>(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(
"Error loading DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]: problem with class file or dependent class", err);
}
}
return strategies;
}
else {
return new LinkedList<T>();
}
}
这个defaultStrategies加载自配置文件,加载过程如下
private static final Properties defaultStrategies;
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
}
}
找到对应位置的配置文件,并且找到关于HandlerAdapter的配置
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
如上所示,容器中HandlerAdapter的时候就会使用配置好的上面的三种HandlerAdapter。如果在spring的配置文件中加入 <mvc:annotation-driven />,则它的实现类AnnotationDrivenBeanDefinitionParser会自动向容器注册RequestMappingHandlerAdapter和RequestMappingHandlerMapping。