《Spring in Action》筆記第五部分,聚焦 Spring MVC 核心啟動流程:DispatcherServlet 初始化順序、三大 HandlerMapping 策略對比、視圖解析器自動發現機制與多映射器責任鏈模式。
| 項目 | Spring MVC | Struts 1.x |
|---|---|---|
| 前端控制器 | DispatcherServlet | ActionServlet |
| 映射配置 | *.htm (慣例) | *.do / *.action |
| 暴露技術 | 隱藏副檔名 | 暴露 .do/.action |
| 上下文載入 | 自動載入 /WEB-INF/[servlet-name]-servlet.xml | struts-config.xml |
| 業務 Bean 注入 | 支援完整依賴注入 | Struts 1.2+ 始支援簡單屬性注入 |
HttpServlet.init(config)
└─ HttpServletBean.init()
└─ FrameworkServlet.initServletBean()
└─ DispatcherServlet.initFrameworkServlet()
├─ initMultipartResolver()
├─ initLocaleResolver()
├─ initThemeResolver()
├─ initHandlerMappings() // 關鍵:載入 HandlerMapping
├─ initHandlerAdapters()
├─ initHandlerExceptionResolvers()
└─ initViewResolvers() // 關鍵:載入 ViewResolver
// DispatcherServlet.initViewResolvers() 簡化邏輯
if (detectAllViewResolvers) { // 預設 true
Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(), ViewResolver.class, true, false);
// 按 order 排序,註冊到 this.viewResolvers
} else {
ViewResolver vr = getApplicationContext().getBean("viewResolver", ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
}
同樣邏輯應用於 HandlerMapping、HandlerAdapter、HandlerExceptionResolver 等組件。
| 映射器 | 映射規則 | 優點 | 缺點 | 推薦度 |
|---|---|---|---|---|
| BeanNameUrlHandlerMapping | Bean name = URL 路徑(/home.html → bean name="/home.html") | 零配置,約定優於配置 | URL 與 Bean 名強綁定,重構困難 | ⭐ 原型/測試 |
| SimpleUrlHandlerMapping | 屬性檔 | 集中管理,關注點分離,支援 order | 需維護映射表 | ⭐⭐⭐⭐⭐ 生產首選 |
| CommonsPathMapHandlerMapping | Controller 類註解 @PathMap("/url") | 程式碼即配置,重構友好 | 侵入業務代碼,屬硬編碼風格 | ⭐⭐ 特定場景 |
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/listCourses.html">listCoursesController</prop>
<prop key="/register.htm">registerStudentController</prop>
</props>
</property>
<property name="order" value="1"/> <!-- 優先級 -->
</bean>
同時註冊多個映射器時,DispatcherServlet 按 order 從小到大遍歷,第一個返回非 null HandlerExecutionChain 者生效。實現 Ordered 介面或設 order 屬性控制優先級。
<bean class="...BeanNameUrlHandlerMapping" p:order="2"/> <!-- fallback -->
<bean class="...SimpleUrlHandlerMapping" p:order="1"/> <!-- 主力 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
Controller 回傳 new ModelAndView("home") → 解析為 /WEB-INF/jsp/home.jsp → RequestDispatcher.forward()。
DispatcherServlet 初始化順序固定,組件自動發現機制統一(detectAll* 預設 true)。SimpleUrlHandlerMapping 集中管理 URL 映射,避免 Bean 名洩露為 URL。order 優先級,構建靈活的責任鏈。