
DispatcherServlet 作用
DispatcherServlet
是前端控制器设计模式的实现,提供 Spring Web MVC 的集中访问点,而且负责职责的分派,而且与 Spring IoC 容器无缝集成,从而可以获得 Spring 的所有好处。DispatcherServlet
主要用作职责调度工作,本身主要用于控制流程,主要职责如下:
- 文件上传解析,如果请求类型是 multipart 将通过
MultipartResolver
进行文件上传解析; - 通过
HandlerMapping
将请求映射到处理器(返回一个 HandlerExecutionChain,它包括一个处理器、多个 HandlerInterceptor 拦截器); - 通过
HandlerAdapter
支持多种类型的处理器(HandlerExecutionChain 中的处理器); - 通过
ViewResolver
解析逻辑视图名到具体视图实现; - 本地化解析;
- 渲染具体的视图等;
- 如果执行过程中遇到异常将交给
HandlerExceptionResolver
来解析
DispathcherServlet 配置详解
1 | <servlet> |
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
:
HandlerMapping
是负责根据 request 请求找到对应的 Handler 处理器及 Interceptor 拦截器,将它们封装在 HandlerExecutionChain
对象中返回给前端控制器。
BeanNameUrlHandlerMapping
:BeanNameUrl 处理器映射器,根据请求的 url 与 Spring 容器中定义的 bean 的 name 进行匹配,从而从 Spring 容器中找到 bean 实例,就是说,请求的 Url 地址就是处理器 Bean 的名字。这个HandlerMapping
配置如下:1
2
3<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" id="handlerMapping">
<property name="beanName" value="/hello"/>
</bean>SimpleUrlHandlerMapping
:是BeanNameUrlHandlerMapping
的增强版本,它可以将 url 和处理器 bean 的 id 进行统一映射配置:1
2
3
4
5
6
7
8<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
也有诸多实现类:
SimpleControllerHandlerAdapter
:简单控制器处理器适配器,所有实现了org.springframework.web.servlet.mvc.Controller
接口的 Bean 通过此适配器进行适配、执行,也就是说,如果我们开发的接口是通过实现 Controller 接口来完成的(不是通过注解开发的接口),那么 HandlerAdapter 必须是SimpleControllerHandlerAdapter
。1
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
HttpRequestHandlerAdapter
:Http 请求处理器适配器,所有实现了org.springframework.web.HttpRequestHandler
接口的 Bean 通过此适配器进行适配、执行。例如存在如下接口:1
2
3
4
5
6
7
public class HelloController2 implements HttpRequestHandler {
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("-----HelloController2-----");
}
}XML 配置如下:
1
2
3
4
5
6
7
8<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 的配置,如果要扫描多个包,多个包之间用 , 隔开即可:
1 | <context:component-scan base-package="com.antoniopeng.hello.spring.mvc"/> |
HandlerMapping
正常情况下,我们在项目中使用的是 RequestMappingHandlerMapping
,这个是根据处理器中的注解,来匹配请求(即 @RequestMapping
注解中的 url 属性)。因为在上面我们都是通过实现类来开发接口的,相当于还是一个类一个接口,所以,我们可以通过 RequestMappingHandlerMapping
来做处理器映射器,这样我们可以在一个类中开发出多个接口。
HandlerAdapter
对于上面提到的通过 @RequestMapping
注解所定义出来的接口方法,这些方法的调用都是要通过 RequestMappingHandlerAdapter
这个适配器来实现。
例如我们开发一个接口:
1 |
|
要能够访问到这个接口,我们需要 RequestMappingHandlerMapping
才能定位到需要执行的方法,需要 RequestMappingHandlerAdapter
,才能执行定位到的方法,修改 springmvc 的配置文件如下:
1 |
|
然后,启动项目,访问 /hello3 接口,就可以看到相应的页面了。
继续优化
由于开发中,我们常用的是 RequestMappingHandlerMapping
和 RequestMappingHandlerAdapter
,这两个有一个简化的写法,如下:
1 | <mvc:annotation-driven> |
可以用这一行配置,代替 RequestMappingHandlerMapping
和 RequestMappingHandlerAdapter
的两行配置。优化后完整配置如下:
1 |
|
访问效果和上一步的效果一样。这是我们实际开发中,最终配置的形态。
更多干货请移步:https://antoniopeng.com
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !