目录
一、HandlerMapping和HandlerAdaptor初始化(initStrategies)
二、常用的HandlerMapping和HandlerAdaptor组合
三、常用的Controller方式
1、RequestMappingHandlerAdapter
2、HttpRequestHandlerAdapter
3、SimpleControllerHandlerAdapter
4、HandlerFunctionAdapter
5、SimpleServletHandlerAdapter
之前分析过九大件中会初始化HandlerMapping和HandlerAdaptor(操作适配器),就是解析各种Controller类型和负责解析调用。Spring允许各种形式初始化Controller,那么对于的接口名称、配置方式等都是不同的。所以需要适配器挨个去适配HttpServletRequest。继续九大件中关于HandlerMapping和HandlerAdaptor的初始化,(之前的版本可能是没有配置就直接调用策略中的,当前版本为5.2.0可能稍微不同,但是主要使用的是@RequestMapping注解的RequestMappingHandlerMapping和RequestMappingHandlerAdapter类型)。
HandlerMapping和HandlerAdaptor的初始化方式基本都一样,只是策略中初始化的类型有所不同。但是必须进行对应,否则doDispatch方法中,HandlerMapping列表遍历解析Controller和HandlerInteceptor链后,需要对应的HandlerAdaptor类型进行解析调用具体的Controller方法。下面是HandlerAdaptor的初始化过程,HandlerMapping类似,如下:
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
// 查询所有的HandlerAdapter类型(默认为true)
if (this.detectAllHandlerAdapters) {
// 擦汗寻BeanFactory中所有的HandlerAdapter类型
Map matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// 按照实现order接口的排序(比如常用的RequestMappingHandlerAdapter
// 就在父类中实现了getOrder为Ordered.LOWEST_PRECEDENCE)
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
} else {
// 省略try catch代码
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
// 最后兜底是静态代码块中策略模式初始化的HandlerAdapter类型
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
}
}
1、如果参数detectAllHandlerAdapters(查询所有HandlerAdapter类型Bean,包括非单利)表示为true,默认为true。直接进行BeanFactory中获取全部,并且按照事先了排序接口返回值进行排序。
2、detectAllHandlerAdapters参数被修改过,则可以直接获取容器中自定义的HANDLER_ADAPTER_BEAN_NAME名称的Bean。之前的版本中只要配置该Bean名称就会使用自定义的。
3、如果上面都没有获取到,则使用静态代码块策略模式加载的DispatcherServlet.properties中的配置HandlerAdapter类型。
但是不论哪种方式,主要常用的适配器有以下几种(现在很少使用xml方式配置了,基本都是使用Spring boot方式,这里也是使用该方式进行demo搭建的,详细地址为:)
1、@RequestMapping注解方式的适配器
RequestMappingHandlerMapping -> RequestMappingHandlerAdapter
2、继承HttpRequestHandler的HTTP请求处理器适配器
BeanNameUrlHandlerMapping -> HttpRequestHandlerAdapter
3、继承Controller接口方式的适配器,现在很少使用了
BeanNameUrlHandlerMapping -> SimpleControllerHandlerAdapter
4、返回RouterFunction类型的适配器
HandlerFunctionAdapter -> RouterFunctionMapping
5、继承自HttpServlet接口,现在已经废弃了
SimpleUrlHandlerMapping -> SimpleServletHandlerAdapter
需要配置不同类型的Controller注册成Bean,这里直接使用@Bean注解而不是xml配置的形式,如下
@Controller
public class BeanController {
@Bean("/controllerAdaptorController")
public ControllerAdaptorController initControllerAdaptorController() {
return new ControllerAdaptorController();
}
@Bean("/httpRequestController")
public HttpRequestController initHttpRequestController() {
return new HttpRequestController();
}
@Bean("simpleServletHandlerAdapter")
public SimpleServletHandlerAdapter initSimpleServletHandlerAdapter() {
return new SimpleServletHandlerAdapter();
}
}
/**
* 适配器类型为: {@link RequestMappingHandlerAdapter}, 处理注解{@link RequestMapping} 类型的方法
* @author lihongmin
* @date 2019/12/26 9:50
* @since 1.0.0
*/
@Controller
public class AnnotationController {
@ResponseBody
@RequestMapping("annotationController")
public String annotationController() {
return "AnnotationController -> @Controller!";
}
}
我们最常用的@RequestMapping注解形式的适配器使用RequestMappingHandlerAdapter类型,后续Spring MVC适配器主要分析该类型的实现过程。
访问地址为:http://127.0.0.1:9999/annotationController
/**
* 适配器类型为: {@link HttpRequestHandlerAdapter},不返回
* {@link ModelAndView} 或者 {@link View}
*
* @author lihongmin
* @date 2019/12/26 9:58
* @since 1.0.0
*/
public class HttpRequestController implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("HttpRequestController -> HttpRequestHandler!");
}
}
访问地址为:http://127.0.0.1:9999/httpRequestController
/**
* 适配器为: {@link SimpleControllerHandlerAdapter} 但是不能
* 与{@link ResponseBody}一起使用(不生效)
*
* @author lihongmin
* @date 2019/12/26 9:40
* @since 1.0.0
*/
public class ControllerAdaptorController implements Controller {
@Override
@ResponseBody
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView("test");
modelAndView.addObject("key", "ControllerAdaptorController -> Controller!");
return modelAndView;
}
}
直接将自己的Controller类实现Controller接口,缺点很明细只有一个接口方法。
访问地址为:http://127.0.0.1:9999/controllerAdaptorController
/**
* 适配器类型为:{@link HandlerFunctionAdapter}
* reactive 相关,当前总是报错MediaType设置问题
* @author lihongmin
* @date 2019/12/26 10:21
* @since 1.0.0
*/
@Configuration
public class HandlerFunctionAdapterController {
@Bean
public RouterFunction testRouterFunction() {
return RouterFunctions.route(RequestPredicates.path("/handlerFunctionAdapter")
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)),
request -> ok().body(fromObject("HandlerFunctionAdapterController ->
HandlerFunctionAdapter!")));
}
}
访问地址为:http://127.0.0.1:9999/handlerFunctionAdapter
/**
* 适配器类型为: {@link SimpleServletHandlerAdapter}
* @author lihongmin
* @date 2019/12/26 9:48
* @since 1.0.0
*/
public class HttpServletController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws IOException {
resp.getWriter().write("HttpServletController -> HttpServlet!");
}
}
访问地址为:http://127.0.0.1:9999/simpleServletHandlerAdapter