DispatcherServlet作用
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 方法就會自動被調用。
4 兩個容器
當 Spring 和 SpringMVC 同時出現,我們的項目中將存在兩個容器,一個是 Spring 容器,另一個是 SpringMVC 容器,Spring 容器通過 ContextLoaderListener 來加載,SpringMVC 容器則通過 DispatcherServlet 來加載,這兩個容器不一樣:
從圖中可以看出:
- ContextLoaderListener 初始化的上下文加載的 Bean 是對於整個應用程序共享的,不管是使用什么表現層技術,一般如 DAO 層、Service 層 Bean;
- DispatcherServlet 初始化的上下文加載的 Bean 是只對 Spring Web MVC 有效的 Bean,如 Controller、HandlerMapping、HandlerAdapter 等等,該初始化上下文應該只加載 Web相關組件。
1. 為什么不在 Spring 容器中掃描所有 Bean?
這個是不可能的。因為請求達到服務端后,找
DispatcherServlet 去處理,只會去 SpringMVC 容器中找,這就意味着
Controller 必須在 SpringMVC 容器中掃描。
2.為什么不在 SpringMVC 容器中掃描所有 Bean?
這個是可以的,可以在
SpringMVC 容器中掃描所有 Bean。不寫在一起,有兩個方面的原因:
- 為了方便配置文件的管理
- 在 Spring+SpringMVC+Hibernate 組合中,實際上也不支持這種寫法