首頁 > 軟體

Springmvc DispatcherServlet原理及用法解析

2020-09-24 06:00:42

DispatcherServlet 是前端控制器設計模式的實現,提供 Spring Web MVC 的集中存取點,而且負責職責的分派,而且與 Spring IoC 容器無縫整合,從而可以獲得 Spring 的所有好處。DispatcherServlet 主要用作職責排程工作,本身主要用於控制流程,主要職責如下:

  • 檔案上傳解析,如果請求型別是 multipart 將通過 MultipartResolver 進行檔案上傳解析;
  • 通過 HandlerMapping,將請求對映到處理器(返回一個 HandlerExecutionChain,它包括一個處理器、多個 HandlerInterceptor 攔截器);
  • 通過 HandlerAdapter 支援多種型別的處理器(HandlerExecutionChain 中的處理器);
  • 通過 ViewResolver 解析邏輯檢視名到具體檢視實現;
  • 在地化解析;
  • 渲染具體的檢視等;
  • 如果執行過程中遇到異常將交給 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-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 組態檔的路徑

Spring設定

先新增一個service包,提供一個HelloService類,如下:

@Service 
public class HelloService { 
	public String hello(String name) { 
		return "hello " + name; 
		} 
}

新增applicationContext.xml

<?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" use-default-filters="true">
    <context:exclude-filter type="annotation"
       expression="org.springframework.stereotype.Controller"/>
  </context:component-scan>
</beans>

這個組態檔預設情況下,並不會被自定載入,所有,需要我們在web.xml對其進行設定

<context-param> 
	<param-name>contextConfigLocation</param-name> 
	<param-value>classpath:applicationContext.xml</param-value> 
</context-param> 
<listener> 
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>

首先通過 context-param 指定 Spring 組態檔的位置,這個組態檔也有一些預設規則,它的組態檔名預設就叫 applicationContext.xml ,並且,如果你將這個組態檔放在 WEB-INF 目錄下,那麼這裡就可以不用指定組態檔位置了,只需要指定監聽器就可以了。這段設定是 Spring 整合 Web 環境的通用設定;一般用於載入除 Web 層的 Bean(如DAO、Service 等),以便於與其他任何Web框架整合。

contextConfigLocation: 表示用於載入Bean的組態檔

contextClass: 表示用於載入 Bean的 ApplicationContext 實現類,預設 WebApplicationContext。

在MyController中注入HelloService:

@org.springframework.stereotype.Controller("/hello")
  public class MyController implements Controller {
    @Autowired
    HelloService helloService;

    /**
     * 這就是一個請求處理介面 
     * * @param req 這就是前端傳送來的請求 
     * * @param resp 這就是伺服器端給前端的響應 
     * * @return 返回值是一個 ModelAndView,Model 相當於是我們的資料模型,
     * View 是我們的檢視 * @throws Exception
     */
    public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
      System.out.println(helloService.hello("javaboy"));
      ModelAndView mv = new ModelAndView("hello");
      mv.addObject("name", "javaboy");
      return mv;
    }
  }

為了在 SpringMVC 容器中能夠掃描到 MyController ,這裡給 MyController 新增了 @Controller 註解,同時,由於我們目前採用的 HandlerMapping 是 BeanNameUrlHandlerMapping(意味著請求地址就是處理器 Bean 的名字),所以,還需要手動指定 MyController 的名字。

最後,修改 SpringMVC 的組態檔,將 Bean 設定為掃描形式:

<context:component-scan base-package="org.javaboy.helloworld" use-default-filters="false">  
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--這個是處理器對映器,這種方式,請求地址其實就是一個 Bean 的名字,然後根據這個 bean 的名字查詢對應的處理器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" id="handlerMapping">  
	<property name="beanName" value="/hello"/>
</bean>

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" id="handlerAdapter"/>
<!--檢視解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">  
	<property name="prefix" value="/jsp/"/>  
	<property name="suffix" value=".jsp"/>
</bean>

設定完成後,再次啟動專案,Spring 容器也將會被建立。存取 /hello 介面,HelloService 中的 hello 方法就會自動被呼叫。

兩個容器

當 Spring 和 SpringMVC 同時出現,我們的專案中將存在兩個容器,一個是 Spring 容器,另一個是 SpringMVC 容器,Spring 容器通過 ContextLoaderListener 來載入,SpringMVC 容器則通過 DispatcherServlet 來載入,這兩個容器不一樣:

從圖中可以看出:

  • ContextLoaderListener 初始化的上下文載入的 Bean 是對於整個應用程式共用的,不管是使用什麼表現層技術,一般如 DAO 層、Service 層 Bean;
  • DispatcherServlet 初始化的上下文載入的 Bean 是隻對 Spring Web MVC 有效的 Bean,如 Controller、HandlerMapping、HandlerAdapter 等等,該初始化上下文應該只載入 Web相關元件。

這個是不可能的。因為請求達到伺服器端後,找DispatcherServlet 去處理,只會去 SpringMVC 容器中找,這就意味著Controller 必須在 SpringMVC 容器中掃描。

2.為什麼不在 SpringMVC 容器中掃描所有 Bean?

這個是可以的,可以在SpringMVC 容器中掃描所有 Bean。不寫在一起,有兩個方面的原因:

  • 為了方便組態檔的管理
  • 在 Spring+SpringMVC+Hibernate 組合中,實際上也不支援這種寫法

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com