• Spring MVC 核心组件详解


    DispatcherServlet 作用


    DispatcherServlet 是前端控制器设计模式的实现,提供 Spring Web MVC 的集中访问点,而且负责职责的分派,而且与 Spring IoC 容器无缝集成,从而可以获得 Spring 的所有好处。DispatcherServlet 主要用作职责调度工作,本身主要用于控制流程,主要职责如下:

    1. 文件上传解析,如果请求类型是 multipart 将通过 MultipartResolver 进行文件上传解析;
    2. 通过 HandlerMapping 将请求映射到处理器(返回一个 HandlerExecutionChain,它包括一个处理器、多个 HandlerInterceptor 拦截器);
    3. 通过 HandlerAdapter 支持多种类型的处理器(HandlerExecutionChain 中的处理器);
    4. 通过 ViewResolver 解析逻辑视图名到具体视图实现;
    5. 本地化解析;
    6. 渲染具体的视图等;
    7. 如果执行过程中遇到异常将交给 HandlerExceptionResolver 来解析

    DispathcherServlet 配置详解


    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    • load-on-startup:表示启动容器时初始化该 Servlet;
    • url-pattern:表示哪些请求交给 Spring Web MVC 处理, "/" 是用来定义默认 servlet 映射的。也可以如 *.html 表示拦截所有以 html 为扩展名的请求;
    • contextConfigLocation:表示 SpringMVC 配置文件的路径。

    其他的参数配置:

    参数 描述
    contextClass 实现 WebApplicationContext 接口的类,当前的 Servlet 用它来创建上下文。如果这个参数没有指定, 默认使用 XmlWebApplicationContext
    contextConfigLocation 传给上下文实例(由 contextClass 指定)的字符串,用来指定上下文的位置。这个字符串可以被分成多个字符串(使用逗号作为分隔符) 来支持多个上下文(在多上下文的情况下,如果同一个bean被定义两次,后面一个优先)。
    namespace WebApplicationContext 命名空间。默认值是 [server-name]-servlet。

    HandlerMapping 处理器映射器


    注意,下文所说的处理器即我们平时所见到的 Controller

    在 SpringMVC 中提供了很多 HandlerMapping

    img

    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>
      
    • SimpleUrlHandlerMapping:是 BeanNameUrlHandlerMapping 的增强版本,它可以将 url 和处理器 bean 的 id 进行统一映射配置:

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

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

    HandlerAdapter 处理器适配器


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

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

    img

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

      <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
      
    • HttpRequestHandlerAdapter:Http 请求处理器适配器,所有实现了 org.springframework.web.HttpRequestHandler 接口的 Bean 通过此适配器进行适配、执行。例如存在如下接口:

      @Controller
      public class HelloController2 implements HttpRequestHandler {
          
          public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              System.out.println("-----HelloController2-----");
          }
      }
      

      XML 配置如下:

      <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" id="handlerMapping">
          <property name="mappings">
              <props>
                  <prop key="/hello2">helloController2</prop>
              </props>
          </property>
      </bean>
      <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" id="handlerAdapter"/>
      

    最佳实践


    各种情况都大概了解了,我们看下项目中的具体实践。

    组件自动扫描

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

    <context:component-scan base-package="com.antoniopeng.hello.spring.mvc"/>
    

    HandlerMapping

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

    HandlerAdapter

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

    例如我们开发一个接口:

    @Controller
    public class HelloController3 {
        
        @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="com.antoniopeng.hello.spring.mvc"/>
    
        <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 接口,就可以看到相应的页面了。

    继续优化

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

    <mvc:annotation-driven>
    

    可以用这一行配置,代替 RequestMappingHandlerMappingRequestMappingHandlerAdapter 的两行配置。优化后完整配置如下:

    <?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="com.antoniopeng.hello.spring.mvc"/>
    
        <!-- 处理器 -->
        <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>
    

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

    更多干货请移步:https://antoniopeng.com

  • 相关阅读:
    文件路径总结
    git本地仓库关联远程仓库
    webpack-dev-server版本
    box-sizing重置
    事件委托优缺点和实现
    移动端经验总结(持续更新)
    点击其他区域关闭dialog
    css3图片变灰
    安装 ubuntu 后,使用 sed 更换国内源
    在virtualBox中打开vdi(转载)
  • 原文地址:https://www.cnblogs.com/antoniopeng/p/14370732.html
Copyright © 2020-2023  润新知