在 Spring web开发中,我们开发方式基本都是使用注解,使用@Controller和@RequestMapping注解完整,但是你有没有发现,为什么SpringMVC中有HandlerAdapter适配器呢?因为你不知道还有其他方式来定义一个Controller.
- 使用 @Controller,@RequestMapping 注解实现
@Controller
public class DemoController {
@RequestMapping("/hello")
public ModelAttribute hello(){
ModelAndView model = new ModelAndView("hello");
model.addObject("hello", "world");
return model;
}
}
- 实现Controller接口
@Controller
public class DemoController2 implements org.springframework.web.servlet.mvc.Controller {
@Override
public ModelAndView handleRequest( HttpServletRequest request, HttpServletResponse response ) throws Exception {
ModelAndView model = new ModelAndView("hello");
model.addObject("hello", "world");
return model;
}
}
但是这个时候就需要配置URL和Controller的关系,在spring.xml中配置
<bean name="/hello" class="com.xx.web.controller.DemoController2 "></bean>
- 实现Servlet接口
public class DemoController3 extends HttpServlet {
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost( HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().write("Hello World.");
}
}
这种方式也需要在xml中配置映射;
在应用启动的 时候,Spring 加载这些Controller类,并解析出URL 对应的处理器handler, 存储到HandlerMapping 里的Map里,当请求到来的时候,DispatcherServlet 首先解析出URL,然后根据URL从HandlerMapping中获取到对应的handler,然后用HandlerAdapter去适配对应的handler,然后去执行handler对应的函数 代码,最后将执行结果返回给客户端。
但是,不同定义的Controller,其 调用的函数不一样,如果是我们自己写,怎么写呢?可以用if else 来处理,代码如下:
Handler handler = handlerMapping.get(URL);
if (handler instanceof Controller) {
((Controller)handler).handleRequest(...);
} else if (handler instanceof Servlet) {
((Servlet)handler).service(...);
} else if (hanlder 对应通过注解来定义的Controller) {
反射调用方法...
}
上述代码的缺点是:如果再增加一个Controller类型,我们需要修改DispatcherServlet代码,在代码中增加一段上述类似的代码。这显然违背开闭原则。
那么Spring中是怎么实现的呢?
Spring 定义了统一的接口HandlerAdapter,并且每种Controller定义了对应的适配器类;
/**
* @desc: 类的描述:处理器适配器 应用到的设计模式:模版方法,适配器模式
*HandlerAdapter
* ---AbstractHandlerMethodAdapter
* ---RequestMappingHandlerAdapter
* ---SimpleServletHandlerAdapter
* ---HttpRequestHandlerAdapter
* ---SimpleControllerHandlerAdapter
*
*/
public interface HandlerAdapter {
/**
* 方法实现说明:判断当前的HandlerAdapter是否支持当前的handler
*/
boolean supports(Object handler);
/**
* 方法实现说明:处理我们的请求 返回ModelAndView
*/
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
我们分析其中一个HandlerAdapter (SimpleControllerHandlerAdapter)
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
// 对应实现 Controller 接口的Handler
@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;
}
}
当我们调用的时候,DispatcherServlet 不用再区分是什么是什么样的handler,只需要获取所有的HandlerAdapter进行适配即可,源码如下:
- 适配器的初始化
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
/**
* 由于我们自己配置了@EnableMvc 所有在配置类中系统会给我们配置几个HandlerApapter
* RequestMappingHandlerAdapter
* SimpleControllerHandlerAdapter
* HttpRequestHandlerAdapter
*/
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 {
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.
}
}
if (this.handlerAdapters == null) {
//默认配置 是通过SpringMvc配置在DispatcherServlet.properties属性文件中
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
}
}
上述代码比较简单,基本意思是 找到Spring容器中配置的HandlerAdapter实现类;
- handler的执行
/**
* 根据Handler选择我们的HandlerAdpater对象
* 默认是@RequestMappingHandlerAdapter对象
*/
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
/**
* 方法实现说明:从我们系统默认的配置的HandlerAdapter 选择支持当前的
* 系统配置配置的@EnableWebMvc
* 默认配置的:
* RequestMappingHandlerAdapter
* SimpleControllerHandlerAdapter
* HttpRequestHandlerAdapter
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//循环我们的系统配置配置的handlerAdapters
if (this.handlerAdapters != null) {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
}
}
总结: 所以HandlerAdapter不是多余,是为了适配不同的Controller而存在的。