Spring 中的 Dispatcher Servlet 是啥?

Posted

技术标签:

【中文标题】Spring 中的 Dispatcher Servlet 是啥?【英文标题】:What is Dispatcher Servlet in Spring?Spring 中的 Dispatcher Servlet 是什么? 【发布时间】:2011-02-15 16:51:30 【问题描述】:

在这张图片中(我从 here 获得),HTTP 请求向 Dispatcher Servlet 发送了一些东西。

我的问题是 Dispatcher Servlet 是做什么的?

是不是类似于从网页中获取信息,然后将其扔给控制器?

【问题讨论】:

【参考方案1】:

您可以说 Dispatcher Servlet 充当任何请求的入口和出口点。每当请求到来时,它首先进入 Dispatcher Servlet(DS),DS 然后尝试识别其处理程序方法(您在控制器中定义的处理请求的方法),一旦处理程序映射器(DS 询问处理程序映射器)返回控制器 Dispatcher servlet 知道可以处理此请求的控制器,现在可以转到此控制器以进一步完成对请求的处理。现在控制器可以用适当的响应进行响应,然后 DS 转到视图解析器以识别视图所在的位置,一旦视图解析器告诉 DS,它就会抓取该视图并将其作为最终响应返回给您。我正在添加一张从 YouTube 频道 Java Guides 获取的图片。

【讨论】:

【参考方案2】:

在 Spring MVC 中,所有传入请求都通过一个 servlet。这个 servlet - DispatcherServlet - 是前端控制器。前端控制器是 Web 应用程序开发中的典型设计模式。在这种情况下,单个 servlet 接收所有请求并将它们传输到应用程序的所有其他组件。

DispatcherServlet 的任务是向特定的 Spring MVC 控制器发送请求。

通常我们有很多控制器,DispatcherServlet 引用以下映射器之一以确定目标控制器:

BeanNameUrlHandlerMapping; ControllerBeanNameHandlerMapping; ControllerClassNameHandlerMapping; DefaultAnnotationHandlerMapping; SimpleUrlHandlerMapping

如果不进行配置,DispatcherServlet默认使用BeanNameUrlHandlerMappingDefaultAnnotationHandlerMapping

当目标控制器被识别时,DispatcherServlet 向它发送请求。控制器根据请求执行一些工作 (或将其委托给其他对象),然后返回 DispatcherServlet 并带有模型和视图的名称。

视图的名称只是一个逻辑名称。然后使用这个逻辑名称来搜索实际的 View(以避免与控制器和特定 View 耦合)。然后DispatcherServlet引用ViewResolver并将View的逻辑名映射到View的具体实现上。

ViewResolver 的一些可能实现是:

BeanNameViewResolver; ContentNegotiatingViewResolver; FreeMarkerViewResolver; InternalResourceViewResolver; JasperReportsViewResolver; ResourceBundleViewResolver; TilesViewResolver; UrlBasedViewResolver; VelocityLayoutViewResolver; VelocityViewResolver; XmlViewResolver; XsltViewResolver.

DispatcherServlet 确定将显示结果的视图时,它将被呈现为响应。

最后,DispatcherServletResponse 对象返回给客户端。

【讨论】:

【参考方案3】:
<?xml version='1.0' encoding='UTF-8' ?>
<!-- was: <?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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
    <context:component-scan base-package="com.demo" />
    <context:annotation-config />

    <mvc:annotation-driven />


    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="datasource" />
    </bean> 

          <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />  
        <property name="url" value="jdbc:mysql://localhost:3306/employee" />
        <property name="username" value="username" />
        <property name="password" value="password" />
    </bean> 

</beans>

【讨论】:

【参考方案4】:

Dispatcher Controller 显示在图中所有传入的请求都被作为前端控制器的 Dispatcher servlet 拦截。 Dispatcher servlet 从 XML 文件中获取到处理程序映射的条目,并将请求转发给 Controller。

【讨论】:

【参考方案5】:

我们可以说像DispatcherServlet 处理 Spring MVC 中的一切。

Web 容器启动时:

    DispatcherServlet 将通过调用加载和初始化 init()方法 init() of DispatcherServlet 将尝试识别 Spring 具有命名约定的配置文档,例如 "servlet_name-servlet.xml" 然后可以识别所有 bean。

例子:

public class DispatcherServlet extends HttpServlet 

    ApplicationContext ctx = null;

    public void init(ServletConfig cfg)
        // 1. try to get the spring configuration document with default naming conventions
        String xml = "servlet_name" + "-servlet.xml";

        //if it was found then creates the ApplicationContext object
        ctx = new XmlWebApplicationContext(xml);
    
    ...

所以,一般DispatcherServlet捕获请求URI并交给HandlerMappingHandlerMapping 使用控制器方法搜索映射 bean,其中控制器返回逻辑名称(视图)。然后这个逻辑名称由HandlerMapping 发送到DispatcherServlet。然后DispatcherServlet 告诉ViewResolver 通过附加前缀和后缀来提供视图的完整位置,然后DispatcherServlet 将视图提供给客户端。

【讨论】:

这是一个很好的解释。您的第 2 点表示 DispatcherServlet 将尝试使用诸如“servlet_name-servlet.xml”之类的命名约定来识别 Spring 配置文档。但是,我见过仅使用“调度程序”之类的名称的项目,并且效果很好。我也试过了。但是不知道为什么?【参考方案6】:

我知道这个问题已经被标记为已解决,但我想添加一张更新的图片来详细解释这种模式(来源:spring in action 4):

说明

当请求离开浏览器(1)时,它会携带有关用户请求内容的信息。至少,请求将携带请求的 URL。但它也可能携带额外的数据,例如用户在表单中提交的信息。

请求传输的第一站是 Spring 的 DispatcherServlet。与大多数基于 Java 的 Web 框架一样,Spring MVC 通过单个前端控制器 servlet 汇集请求。前端控制器是一种常见的 Web 应用程序模式,其中单个 servlet 将请求的责任委托给应用程序的其他组件以执行实际处理。在 Spring MVC 的情况下,DispatcherServlet 是前端控制器。 DispatcherServlet 的工作是将请求发送到 Spring MVC 控制器。控制器是处理请求的 Spring 组件。但是一个典型的应用程序可能有多个控制器,并且 DispatcherServlet 需要一些帮助来决定将请求发送到哪个控制器。因此 DispatcherServlet 查询一个或多个处理程序映射 (2) 以确定请求的下一站将在哪里。处理程序映射在做出决定时特别注意请求携带的 URL。 一旦选择了合适的控制器,DispatcherServlet 就会以愉快的方式将请求发送到所选控制器(3)。在控制器处,请求丢弃其有效负载(用户提交的信息)并耐心等待控制器处理该信息。 (实际上,一个设计良好的控制器本身很少或不执行任何处理,而是将业务逻辑的责任委托给一个或多个服务对象。) 控制器执行的逻辑通常会导致一些信息需要带回给用户并显示在浏览器中。此信息称为模型。但是将原始信息发送回用户是不够的——它需要以用户友好的格式进行格式化,通常是 html。为此,需要将信息提供给视图,通常是 JavaServer Page (JSP)。 控制器做的最后一件事是打包模型数据并识别应该呈现输出的视图的名称。然后它将请求连同模型和视图名称一起发送回 DispatcherServlet (4)。 为了使控制器不与特定视图耦合,传递回 DispatcherServlet 的视图名称不会直接标识特定的 JSP。它甚至不一定表明该视图是一个 JSP。相反,它只带有一个逻辑名称,用于查找将产生结果的实际视图。 DispatcherServlet 咨询视图解析器 (5) 以将逻辑视图名称映射到特定的视图实现,该实现可能是也可能不是 JSP。 现在 DispatcherServlet 知道哪个视图将呈现结果,请求的工作就快结束了。它的最后一站是视图实现(6),通常是一个 JSP,它提供模型数据。请求的工作终于完成了。视图将使用模型数据来渲染输出,这些输出将由(不太勤奋的)响应对象 (7) 传送回客户端。

【讨论】:

我有一个问题,如果返回我们在浏览器中看到的 JSON 对象,它如何选择视图,如果没有选择逻辑视图,它是否返回相同的 URI? @Nesrin 自从你问以来已经很久了,但这里有一个答案:你在 @Controller 方法上方放置了一个特殊的注释,称为 @ResponseBody,表明返回的响应应该直接写在 HTTP 响应正文上,不得放置在模型中或作为视图解析。【参考方案7】:

DispatcherServlet 的工作是获取传入的 URI 并找到组合的处理程序(通常是 Controller 类上的方法)和视图(通常是 JSP)的正确组合形成应该在该位置找到的页面或资源。

我可能有

一个文件/WEB-INF/jsp/pages/Home.jsp

和一个类上的方法

@RequestMapping(value="/pages/Home.html")
private ModelMap buildHome() 
    return somestuff;

Dispatcher servlet 是“知道”在浏览器请求页面时调用该方法,并将其结果与匹配的 JSP 文件组合以生成 html 文档的位。

它如何实现这一点因配置和 Spring 版本而异。

也没有理由最终结果必须是网页。它可以做同样的事情来定位 RMI 端点,处理 SOAP 请求,任何可以进入 servlet 的东西。

【讨论】:

很好的回击,现在的问题是 DispatcherServlet 是如何识别类名和方法名的。你能告诉我一个配置示例,其中我有两个类和两个方法名,以及 DispatcherServlet 如何捕获正确的请求。 它实际上在启动时扫描类路径以查找该注释并将“/pages/Home.html”映射到类+方法。如果您有两个方法都具有“/pages/Home.html”,并且注释中没有其他限制,那将是一个错误,它会向您抛出异常。如果你是老派,你也可以将它与 XML 连接起来。 在使用基于注释的@RestController 时是否需要Dispatcher Servlet xml 文件? web.xml 中的@viper 我们总是需要配置调度程序 servlet,即使您使用注释或 xml 配置 还有其他类型的servlet吗?【参考方案8】:

DispatcherServlet 是 Spring MVC 对 front controller pattern 的实现。

请参阅 Spring 文档 here 中的说明。

本质上,它是一个 servlet,它接受传入的请求,并将该请求的处理委托给多个处理程序之一,其映射在 DispatcherServlet 配置中是特定的。

【讨论】:

它是否类似于 Flex 中的事件,在其中我将调度事件从一个 MXML 发送到另一个 MXML 或发送到服务器。我的应用程序中可以有多个 DispatcherServlet。是否每个类文件都有单独的 DispatcherServlet。 通常只有一个前置控制器。这与您拥有的模型和视图无关。它只是将特定的模型和视图结合在一起。 @theband:你可以拥有多个DispatcherServlets,如果你的架构这样更有意义,但通常没有理由这样做。

以上是关于Spring 中的 Dispatcher Servlet 是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Spring MVC 无法正确配置 Dispatcher Servlet

Spring Integration Dispatcher 没有频道订阅者

Spring:在名称为“dispatcher”的 DispatcherServlet 中找不到带有 URI [] 的 HTTP 请求的映射

Java、Spring、Apache Tiles 错误:无法解析名称为“dispatcher”的 servlet 中名称为“index”的视图

Dispatcher 没有频道订阅者 - spring-cloud-stream-kafka

Spring MVC 配置文件dispatcher-servlet.xml 文件详解