SpringMvc之HandlerMapping详解

 更新时间:2023年08月31日 10:39:37   作者:猎户星座。  
这篇文章主要介绍了SpringMvc之HandlerMapping详解,Handler可以理解为具体干活的,也就是我们的业务处理逻辑,Handler最终是要通过url 来访问到,这样url 与Handler之间就有一个映射关系了,需要的朋友可以参考下

一、Handler与HandlerMapping关系

Handler可以理解为具体干活的,也就是我们的业务处理逻辑。

Handler最终是要通过url 来访问到,这样url 与Handler之间就有一个映射关系了。

HandlerMapping的作用就是维护这种映射,对Handler登记在册,对外提供根据url 查询Handler的服务。

二、Handler分类

SpringMVC为我们提供了多种定义Handler的方式。

1.实现Controller接口

org.springframework.web.servlet.mvc.Controller 接口是SpringMvc提供的控制器接口,实现此接口的类,可以看做是一个Handler。

此接口只有一个方法

public interface Controller {
    ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

实现了此接口的Handler特点就是: 只有一个handleRequest方法接受请求,也就是说大部分情况下,一个类是一个handler,一个类只能映射一个URL。

针对一些场景,SpringMVC提供了几个Controller的默认实现:

与Servlet相关

  • ServletForwardingController 与Servlet有关的控制器,作用:将到达ServletForwardingController的请求转发到当前应用中的一个Servlet。
  • ServletWrappingController 与Servlet有关的控制器,作用:将当前应用中的某个 Servlet直接包装为一个Controller,所有到达ServletWrappingController的请求最终交给其包装的那个servlet进行处理

直接跳转页面

  • ParameterizableViewController 用于直接界面跳转,省去自己实现Controller。控制器根据配置的参数来跳转界面。
  • UrlFilenameViewController 用于直接界面跳转,省去自己实现Controller。控制器根据请求的URL直接解析出视图名。

MultiActionController

一个 Controller 可以写多个方法,分别对应不同的请求,使同一业务的方法可以放在一起了。在使用时让自己的 Controller 类继承 MultiActionController 类。(注意,虽然处理了多个请求但还是只有一个handleRequest接受的请求。此类类似分发功能)

2.实现HttpRequestHandler接口

此接口与Controller类似,也是只有一个handlerRequest方法.

public interface HttpRequestHandler {
    void handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException;
}

但是handleRequest 并没有返回一个视图。从这点来看

HttpRequestHandler是专门处理Http请求(非视图请求),并生成对应的响应的处理器。

针对一些场景,SpringMVC提供了几个HttpRequestHandler的默认实现:

静态资源相关

静态资源的请求也web开发中不可或缺的请求.HttpRequestHandler的两个实现类,针对静态资源进行处理。

  • DefaultServletHttpRequestHandler  与静态资源有关的控制器。

通常web容器都有处理静态资源请求的能力。

我们以Tomcat为例,Tomcat中所有的资源都是Servlet实现的,静态资源的请求交类DefaultServlet去处理。

  • DefaultServletHttpRequestHandler的作用其实就是根据当前容器,将静态资源请求转给容器自己去处理静态资源。

例如:Tomcat容器下,DefaultServletHttpRequestHandler将静态资源请求交给DefaultServlet去处理

  • ResourceHttpRequestHandler  与静态资源有关的控制器。
  • DefaultServletHttpRequestHandler把静态资源请求交给容器处理。
  • ResourceHttpRequestHandler是把静态资源请求交给SpringMVC自己处理。

我们通常用注解的形式配置静态资源的处理

@Configuration
public class WebMvcStaticResourcesConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        if (!registry.hasMappingForPattern("/static/**")) {
            registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        }
        super.addResourceHandlers(registry);
    }
}

此时我们心里应该清楚:这是交给SpringMVC自己处理静态资源请求远程访问相关。

针对远程访问的场景,Spring不但自己做了实现,而且还提供了对其他技术的集成支持。

  • Spring HTTP Invoker: Spring自己实现,使用HTTP协议,允许穿透防火墙,使用JAVA系列化方式,但仅限于Spring应用之间使用,即调用者与被调用者都必须是使用Spring框架的应用。
  • RMI:使用JRMP协议(基于TCP/IP),不允许穿透防火墙,使用JAVA系列化方式,使用于任何JAVA应用之间相互调用。
  • Hessian:使用HTTP协议,允许穿透防火墙,使用自己的系列化方式,支持JAVA、C++、.Net等跨语言使用。
  • Burlap: 与Hessian相同,只是Hessian使用二进制传输,而Burlap使用XML格式传输(两个产品均属于caucho公司的开源产品)。

SpringMVC提供的几个HttpRequestHandler实现,正是处理这类请求。

  • HttpInvokerServiceExporter
    支持 Spring HTTP Invoker 调用器
  • HessianServiceExporter
    hessian服务处理程序
  • BurlapServiceExporter
    Burlap服务处理程序

3.实现Servlet方式

Servlet是我们使用最早的定义业务逻辑的方式。SpringMVC也提供了对这种实现方式的支持

@Controller("/servletController")
public class ServletController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("this servlet controller");
    }
}

4.@RequestMapping方式

这种方式是我们现在最熟悉的方式。一个方法就是一个handler, 一类中可以写多个handler。

@RestController
@RequestMapping(value = "/test")
public class TestController {
        @RequestMapping(value = "/test")
        public void getCode()throws  Exception{
            System.out.println("this RequestMapping");
        }
}

对于springMVC提供的定义Handler的这些方式,我们可以灵活的定义我们的业务处理。

三、HandlerMapping

定义了完了Handler,我们最终的目的还是需要通过url访问到他们进行业务的处理。

此时HandlerMapping上场。HandlerMapping 会把他们,按照url 与Handler的映射关系登记在册。我们就可以通过url找到对应的Handler了。

HandlerMapping 接口,只定义了一个方法getHandler。

此方法是各种HandlerMapping实现类对外提供获取Handler的核心方法

public interface HandlerMapping {
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

上文可以看出: 一个handler可能是一个方法,也可能是一个 Controller 对象、 HttpRequestHandler 对象或 Servlet 对象 。

针对这种情况, HandlerMapping分为两个分支来处理

  • AbstractHandlerMethodMapping:一种是处理url直接与类级别handler的对应。
  • AbstractUrlHandlerMapping一种是处理url与Method级别handler的对应。

它们又统一继承于 AbstractHandlerMapping

AbstractHandlerMapping

AbstractHandlerMapping 是HandlerMapping的抽象实现,使用 模板模式 定义了获取Handler的算法骨架

 public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
   Object handler = getHandlerInternal(request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
        return executionChain;
 }

可以看到在这个方法中又调用了 getHandlerInternal() 方法获取到了 Handler 对象,而 Handler 对象具体内容是由它的子类去定义的。

算法骨架:

  • 获取到一个handler
  • 将handler与拦截器包装成一个HandlerExecutionChain 实例返回 AbstractUrlHandlerMapping

AbstractUrlHandlerMapping

这个分支获取的 Handler 的类型实际就是一个 Controller 类,处理url直接与类handler的映射。(也就是一个类中只有一个接受请求的方法)

常见handlerMapping实现:

  • BeanNameUrlHandlerMapping 利用 BeanName 来作为 URL 使用。并继承AbstractDetectingUrlHandlerMapping类,说明其具有检查url的能力。我们使用@Controller注解标识( Controller接口方式,Servlet方式,HttpRequestHandler接口方式 )handler的beaname,通过beanname访问到handler
  • SimpleUrlHandlerMapping 可以将 URL 与处理器的定义分离,还可以对 URL 进行统一的映射管理。怎么理解呢? 说白了就是我们把我们定义的url与handler的关系配置到此handlerMapping.urlMap属性上,统一管理。

AbstractHandlerMethodMapping

AbstractHandlerMethodMapping 这个分支获取的 Handler 的类型是 HandlerMethod,即这个 Handler 是一个方法,它保存了方法的信息(如Method),这样一个 Controller 就可以处理多个请求了

AbstractHandlerMethodMapping只有一个实现类 RequestMappingHandlerMapping

handlerMapping实现:

  • RequestMappingHandlerMapping:处理@RequestMapping 这种方式的handler 。

四、总结

在我们使用springmvc时:

我们在写接口时,其实就是在定义handler,并配置一个Url与之映射。

springmvc 为我们提供了4种定义handler的形式我们定义handler 被HandlerMapping登记在册,这样我们就可以使用url从HandlerMapping找到对应handler。

这就是Handler与HandlerMapping的关系了。

到此这篇关于SpringMvc之HandlerMapping详解的文章就介绍到这了,更多相关SpringMvc的HandlerMapping内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Intellij Idea中批量导入第三方jar包的全过程

    Intellij Idea中批量导入第三方jar包的全过程

    引入jar包一般都是针对小的java项目,这篇文章主要给大家介绍了关于Intellij Idea中批量导入第三方jar包的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2021-10-10
  • java中字符串替换常用的4种方法

    java中字符串替换常用的4种方法

    在Java中String类提供了许多方便的方法来处理字符串,下面这篇文章主要给大家介绍了关于java中字符串替换常用的4种方法,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • Java设计模式之浅谈外观模式

    Java设计模式之浅谈外观模式

    这篇文章主要介绍了Java设计模式之外观模式的相关资料,需要的朋友可以参考下
    2022-09-09
  • 使用Spring自定义注解实现任务路由的方法

    使用Spring自定义注解实现任务路由的方法

    本篇文章主要介绍了使用Spring自定义注解实现任务路由的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • 老生常谈java中的数组初始化

    老生常谈java中的数组初始化

    下面小编就为大家带来一篇老生常谈java中的数组初始化。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • Java设计模式之享元模式(Flyweight Pattern)详解

    Java设计模式之享元模式(Flyweight Pattern)详解

    享元模式(Flyweight Pattern)是一种结构型设计模式,旨在减少对象的数量,以节省内存空间和提高性能,本文将详细的给大家介绍一下Java享元模式,需要的朋友可以参考下
    2023-07-07
  • java中单双斜杠的使用图文详解

    java中单双斜杠的使用图文详解

    JAVA中的斜杠有正斜杠与反斜杠之分,正斜杠,一般就叫做斜杠,下面这篇文章主要给大家介绍了关于java中单双斜杠使用的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • 详解如何使用Mybatis的拦截器

    详解如何使用Mybatis的拦截器

    MyBatis 拦截器是 MyBatis 提供的一个强大特性,它允许你在 MyBatis 执行其核心逻辑的关键节点插入自定义逻辑,从而改变 MyBatis 的默认行为,本文给大家详细介绍了如何使用Mybatis的拦截器,需要的朋友可以参考下
    2024-03-03
  • java 增强型for循环语法详解

    java 增强型for循环语法详解

    增强型 for 循环(也称为 “for-each” 循环)是 Java 从 JDK 5 开始引入的一种便捷循环语法,旨在简化对数组或集合类的迭代操作,这篇文章主要介绍了java 增强型for循环 详解,需要的朋友可以参考下
    2025-04-04
  • Java中Druid连接池连接超时获取不到连接的解决

    Java中Druid连接池连接超时获取不到连接的解决

    这篇文章主要介绍了Java中Druid连接池连接超时获取不到连接的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11

最新评论