HandlerMapping可以完成URL与Handler之间的映射关系,那么HandlerAdapter就可以帮助自定义各种Handler了。因为Spring MVC首先帮助我们把特别的URL对应到一个Handler,那么这个Handler一定是符合某一种规律,最常见的办法就是我们所有的Handler都继承某一个接口,然后Spring MVC就调用这个接口中定义的特殊方法。
但是Spring MVC提供了另一种方式,可以不固定Handler这个接口类,也就是URL对应的Handler可以实现多个接口,每个接口可以定义不同的方法。
HandlerAdapter类相关的结构图
HandlerAdapter的初始化程序
从名字联想也知道这是一个典型的适配器模式的使用。适配器模式将一个类的接口适配成用户所期待的。使用适配器,可以使接口不兼容而无法在一起工作的类协同工作,做法是将类自己的接口包裹在一个已存在的类中。DispatcherServlet在初始化HandlerAdapter时做了哪些内容呢?
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对象创建出来保存在DispatcherServlet的handlerAdapters集合中。和HandlerMapping一样,同样在初始化的过程中涉及到一个变量detectAllHandlerAdapters,可通过设置该值为false来强制系统只加载bean name为“handlerAdapter”的对象。
如果没有定义HandlerAdapter的话,Spring MVC就会按照DispatcherServlet.properties所定义的内容来加载默认的HandlerAdapter。但前面一篇HandlerMapping没有仔细分析如何来加载默认信息,这边着重分析一下。
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>();
}
}
通过getDefaultStrategies()方法,Spring会从defaultStrategies中加载对应的HandlerAdapter的属性,那么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());
}
}
通过DispatcherServlet的静态代码块可知,在系统加载的时候,defaultStrategies根据当前路径DispatcherServlet.properties来初始化本身。
HandlerAdapter相关类分析
DispatcherServlet.properties中对应HandlerAdapter的属性HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter三种。
作为总控制器的servlet通过处理器映射得到处理器后,会轮询处理器适配器模块,查找能够处理当前请求的处理器的实现,处理器适配器模块根据处理映射返回的处理器类型,来选择某一个适当的适配器的实现。
- HTTP请求处理器适配器(HttpRequestHandlerAdapter)
HTTP请求处理器适配器仅仅支持对HTTP请求处理器的适配。它简单的将HTTP请求对象和响应对象传递给HTTP请求处理器的实现,它并不需要返回值。它主要应用于基于HTTP的远程调用的实现上。
所有的Handler需实现HttpRequestHandler接口,并实现其void handlerRequest(HttpRequest,HttpResponse)方法,该方法没有返回值。
- 简单控制器处理器适配器(SimpleControllerHandlerAdapter)
这个实现类将HTTP请求适配到一个控制器的实现进行处理。这里的控制器的实现是一个简单的控制器接口的实现。简单控制器处理器适配器被设计成一个框架类的实现,不需要被改写,客户化的业务逻辑通常是在控制器接口的实现类中实现的。
所有的Handler需实现Controller接口,并实现其ModelAndView handler(HttpRequest,HttpResponse,handler)方法,该方法返回ModelAndView对象,用于后续的模板渲染。
- 注解方法处理器适配器(AnnotationMethodHandlerAdapter)
这个类的实现是基于注解的实现,它需要结合注解方法映射和注解方法处理器协同工作。它通过解析声明在注解控制器的请求映射信息来解析响应的处理器方法来处理当前的HTTP请求。在处理的过程中,它通过反射来发现探测处理器方法的参数,调用处理器方法,并且映射返回值到模型和控制器对象,最后返回模型和控制器对象给作为主控制器的派遣器Servlet。
总而言之,Spring中所使用的Handler并没有任何特殊的联系,但为了统一处理,Spring提供了不同情况下的适配器。这样,Handler的实现更加灵活,不需要和其它框架一样只能和某一个Handler接口绑定起来。