User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Spring   ›   SpringMVC   ›   正文
SpringMVC

SpringMVC笔记5—处理器详解

2020-04-05 01:14:29
790  0 1
参考目录 隐藏
1) 1.HandlerMapping
2) 2.HandlerAdapter
3) 具体实践
4) 关于 <mvc:annotation-driven> 补充:
5) RequestMappingHandlerMapping

阅读完需:约 8 分钟

1.HandlerMapping

(PS:处理器即我们平时所见到的 Controller)

HandlerMapping ,中文译作处理器映射器,在 SpringMVC 中,系统提供了很多 HandlerMapping:

HandlerMapping 是负责根据 request 请求找到对应的 Handler 处理器及 Interceptor 拦截器,将它们封装在 HandlerExecutionChain 对象中返回给前端控制器。

  • BeanNameUrlHandlerMapping

BeanNameUrl 处理器映射器,根据请求的 url 与 Spring 容器中定义的 bean 的 name 进行匹配,从而从 Spring 容器中找到 bean 实例,就是说,请求的 Url 地址就是处理器 Bean 的名字。

这个 HandlerMapping 配置如下:

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" id="handlerMapping">
    <property name="beanName" value="/hello"/>
</bean>

写法2:

BeanNameUrlHandlerMapping.class(注册器映射器 bean节点的class属性中用到的,这种方式dean id属性必须要以“/”开头)

  • SimpleUrlHandlerMapping

SimpleUrlHandlerMapping 是 BeanNameUrlHandlerMapping 的增强版本,它可以将 url 和处理器 bean 的 id 进行统一映射配置:

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" id="handlerMapping">
    <property name="mappings">
        <props>
            <prop key="/hello">myController</prop>
            <prop key="/hello2">myController2</prop>
        </props>
    </property>
</bean>

注意,在 props 中,可以配置多个请求路径和处理器实例的映射关系。

2.HandlerAdapter

HandlerAdapter,中文译作处理器适配器。

HandlerAdapter 会根据适配器接口对后端控制器进行包装(适配),包装后即可对处理器进行执行,通过扩展处理器适配器可以执行多种类型的处理器,这里使用了适配器设计模式。

在 SpringMVC 中,HandlerAdapter 也有诸多实现类:

  • SimpleControllerHandlerAdapter

SimpleControllerHandlerAdapter 简单控制器处理器适配器,所有实现了 org.springframework.web.servlet.mvc.Controller 接口的 Bean 通过此适配器进行适配、执行,也就是说,如果我们开发的接口是通过实现 Controller 接口来完成的(不是通过注解开发的接口),那么 HandlerAdapter 必须是 SimpleControllerHandlerAdapter。

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
  • HttpRequestHandlerAdapter

HttpRequestHandlerAdapter,http 请求处理器适配器,所有实现了 org.springframework.web.HttpRequestHandler 接口的 Bean 通过此适配器进行适配、执行。

例如存在如下接口:

@Controller
public class MyController2 implements HttpRequestHandler {
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("-----MyController2-----");
    }
}
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" id="handlerMapping">
    <property name="mappings">
        <props>
            <prop key="/hello2">myController2</prop>
        </props>
    </property>
</bean>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" id="handlerAdapter"/>

具体实践

  • 组件自动扫描

web 开发中,我们基本上不再通过 XML 或者 Java 配置来创建一个 Bean 的实例,而是直接通过组件扫描来实现 Bean 的配置,如果要扫描多个包,多个包之间用 , 隔开即可:

<context:component-scan base-package="org.sang"/>
  • HandlerMapping

正常情况下,我们在项目中使用的是 RequestMappingHandlerMapping,这个是根据处理器中的注解,来匹配请求(即 @RequestMapping 注解中的 url 属性)。因为在上面我们都是通过实现类来开发接口的,相当于还是一个类一个接口,所以,我们可以通过 RequestMappingHandlerMapping 来做处理器映射器,这样我们可以在一个类中开发出多个接口。

  • HandlerAdapter

对于上面提到的通过 @RequestMapping 注解所定义出来的接口方法,这些方法的调用都是要通过 RequestMappingHandlerAdapter 这个适配器来实现。

例如我们开发一个接口:

@Controller
public class MyController3 {
    @RequestMapping("/hello3")
    public ModelAndView hello() {
        return new ModelAndView("hello3");
    }
}

要能够访问到这个接口,我们需要 RequestMappingHandlerMapping 才能定位到需要执行的方法,需要 RequestMappingHandlerAdapter,才能执行定位到的方法,修改 springmvc 的配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.javaboy.helloworld"/>

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" id="handlerMapping"/>
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" id="handlerAdapter"/>
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
        <property name="prefix" value="/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

然后,启动项目,访问 /hello3 接口,就可以看到相应的页面了。

  • 继续优化

由于开发中,我们常用的是 RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter ,这两个有一个简化的写法,如下:

<mvc:annotation-driven>

可以用这一行配置,代替 RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter 的两行配置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="org.javaboy.helloworld"/>

    <mvc:annotation-driven/>
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
        <property name="prefix" value="/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

访问效果和上一步的效果一样。这是实际开发中,最终配置的形态。

关于 <mvc:annotation-driven> 补充:

有时候我们没有写这个 <mvc:annotation-driven > 程序还是可以运行没有报错这是为什么呢?

这个在springmvc选中的配置不是不是必须的。这个注解驱动主要是配置RequestMappingHandlerMapping和RequestMappingHandlerAdapter。但是springmvc容器启动是会加载默认的DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter如图:

所以不配置也是不影响项目的启动的。但是这连个默认的方法又是过时的方法看源代码如图:

所以过时的方法虽然可用,但是我们一般会配置新的代替的方法。然后中又包含所代替的方法。所以不配置不会影响项目,但是我们一般都会配置。

最重要的前两个组件配置已包含在spring的默认配置文件中,所以可以不用配置也能正常运行。但spring一旦检测到用户配置了相关组件就不会再使用默认配置。


RequestMappingHandlerMapping

这个是项目中写jar包时遇到的问题,通过这个类解决!

关系梳理

  1. spring ioc 是spring的核心,用来管理spring bean的生命周期
  2. MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式
  3. spring mvc 是spring的一个独立的模块,就像AOP一样

在spring mvc中把web框架和spring ioc融合在一起,是通过ContextLoaderListener监听servlet上下文的创建后来加载父容器完成的,然后通过配置一个servlet对象DispatcherServlet,在初始化DispatcherServlet时来加载具体子容器

关于我们今天要讲的RequestMappingHandlerMapping也是在DispatcherServlet的初始化过程中自动加载的,默认会自动加载所有实现HandlerMapping接口的bean,且我们可以通过serOrder来设置优先级,系统默认会加载RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping 并且按照顺序使用


RequestMappingHandlerMapping实现了InitializingBean接口,在其初始化时执行afterPropertiesSet方法。在此方法中其遍历ApplicationContext中所有Bean,通过反射判断其类型Class上是否有@Controller或@RequestMapping注解。

若Class上有此类注解说明这个Bean是Controller。则执行detectHandlerMethods(beanName)方法,反射(clazz.getMethods())并遍历此Bean的Method[],通过反射method.getAnnotation(RequestMapping)判断并获取方法上标注的@RequestMapping配置信息。将@RequestMapping信息封装成RequestMappingInfo,将此method封装成HandlerMethod。注册到RequestMappingHandlerMapping的mappingRegistry中。

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

1 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 593842浏览

随机文章
Vue关于路由拦截
5年前
HTTP中GET,POST和PUT等方法的区别
5年前
MyBatis笔记12—动态 SQL
5年前
Ajax简介和发送异步请求(四步操作)
5年前
Java—ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量
5年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 593842 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付