Spring MVC中的HandlerMapping与HandlerAdapter

Spring MVC中的HandlerMapping与HandlerAdapter的关系

最近和同事讨论一个spring mvc的问题,问到HandlerMapping与HandlerAdapter有什么关系?虽然使用spring mvc时间也不短,但是瞬间能起来的只有两个关键词:

@RequestMapping,这个经常用的,每个 Controller下面的action方法上一般都会定义一个特有的url路径。当HTTP请求请求发送到服务端后会根据url来查找应该执行哪个Controller下面的哪个action,我理解为url与java代码的一个路由关系。

@RequestMapping(value = "/bss/{priceId}", method = RequestMethod.GET) public ValueResult<ProductPrice> getProductPrice(HttpServletRequest request, @Min(value = 1,message = "priceId不合法") @PathVariable final long priceId) { //省略 }

HandlerInterceptor,这个也是经常用的,做请求拦截时比较常用。

上面两个关键词尽管与问题有所关联,但很明显不是主要的,核心还是这两个接口都是做什么的,两者之间有什么互动。于是我们可以从一个请求开始调试下spring mvc的调用过程,以此来分析它们的作用以及关系。

Spring MVC配置 两个配置文件:

应用程序级别的applicationContext.xml,一般加载非web的配置,比如数据库配置,redis配置等等。

web级别的mvc-dispatcher-servlet.xml,这里专注mvc的配置。

XmlWebApplicationContext context = new XmlWebApplicationContext(); context.setConfigLocations(new String[]{"classpath*:applicationContext.xml","classpath*:spring/mvc-dispatcher-servlet.xml"}); ServletContextHandler spingMvcHandler = new ServletContextHandler(); spingMvcHandler.setContextPath(appConfig.getContext()); spingMvcHandler.addEventListener(new ContextLoaderListener(context)); spingMvcHandler.addServlet(new ServletHolder(new DispatcherServlet(context)), "/*");

这里引用《张开涛》同学的图来说明上面两个配置的作用以及关系:

 

Spring MVC中的HandlerMapping与HandlerAdapter

两个核心类

ContextLoaderListener
这的作用主要是在启动web容器时加载ApplicationContext的信息,用来创建ROOT ApplicationContext的,可以接收XML类型的,比如XmlWebApplicationContext,它将从XML配置文件中加载配置信息。

这篇它不是重点至此主止。

DispatcherServlet
也叫前端控制器,它是Spring MVC的统一访问入口,负责职责的分配以及工作调试,由于它的功能复杂这里只关心与HandlerMapping与HandlerAdaper的内容。下面是初始化的功能,其中有初始化HandlerMapping与HandlerAdaper。

@Override 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) { //其它初始化 initHandlerMappings(context); initHandlerAdapters(context); //其它初始化 }

initHandlerMappings,主要是调用BeanFactoryUtils.beansOfTypeIncludingAncestors,其中一种非常重要的HandlerMapping是RequestMappingHandlerMapping,我们通过在Controller方面上加@RequestMapping注释来配合使用,系统会将我们配置的RequestMapping信息注册到其中,详细数据参数此图:mappingRegistry中包含了所有的请求路由信息。

Spring MVC中的HandlerMapping与HandlerAdapter

代码如下:

private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; 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<HandlerMapping>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } } //不加载全部的先省略 //加载默认的逻辑先省略 }

DispatcherServlet核心方法:doDispatch,三个重要步骤:

getHandler,获取页面处理器,通俗点就是获取由哪个Controller来执行,包含方法信息以及方法参数等信息。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/76ed2d4f6e0996f256985ce81f188d0c.html