Spring MVC AbstractAnnotationConfigDispatcherServletInitializer


Spring MVC AbstractAnnotationConfigDispatcherServletInitializer 用於 DispatcherServlet 初始化

DispatcherServlet 是 Spring MVC 的核心組件,它是一個 request 首先到達的地方,負責 request 在其他各個組件間的傳遞加工,在過去,像 DispatcherServlet 這樣的 servlets 是使用 web.xml 文件配置的。

基於 Servlet 3 和 Spring 3.1 的一些新特性,我們可以用更簡單的方式來配置,即使用 Java 代碼。

簡單來說,AbstractAnnotationConfigDispatcherServletInitializer 自動被加載,負責應用程序中 servlet 上下文中的 DispatcherServlet 和 Spring 其他上下文的配置。

Spring MVC提供基類 AbstractAnnotationConfigDispatcherServletInitializer,用於 DispatcherServlet 初始化(實現了WebApplicationInitializer接口),該基類既要完成 WebApplicationInitializer 接口中配置servlet容器的功能,又完成了配置MVC的功能,即同時配置了 DispatcherServlet 和 ContextLoaderListener 。

 

package com.it.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    /*
    加載 Spring 配置類中的信息,
    初始化 Spring 容器
   */
    protected Class<?>[] getRootConfigClasses() {  //配置root上下文,如Jpa數據源等等的配置
return new Class[]{SpringConfig.class}; }
/* 加載 Spring MVC 配置類中的信息, 初始化 Spring MVC 容器 */ protected Class<?>[] getServletConfigClasses() {//配置dispatcher servlet,如果在root config指定了該轉發規則就可以忽略

return new Class[]{SpringMvcConfig.class}; }
//配置 DispatcherServlet 的映射路徑 //指定開始被 servlet 處理的url,配置從 / 開始
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

 

getServletMappings() 的進一步說明:

通常情況下,大家配置spring mvc的路徑攔截(ServletMapping)都習慣配置“/”,但在某些特殊場景下,你可能希望所有的mvc的路徑都有個固定的前綴,形如“/springmvc/*”,如果你在springmvc的ServletMapping中配置了這種路徑,那么你的URL訪問地址和controller的path就要注意了:如果你的地址欄URL為"/springmvc/user",那么你的controller中的path就必須配置"/user",因為spring mvc攔截了所有以“/springmvc”為前綴的請求,而在匹配的時候也截掉了“/springmvc”,用剩下的“/user”匹配controller。
如果路徑設置為“/”,則所有的請求都會由DispatcherServlet處理。

 

如何取代傳統的 web.xml 搭建Spring MVC,DispatcherServlet 是 Spring MVC 的核心,我們都會把它放在 web.xml 文件中,但是自從有了 Servlet 3 規范和 Spring 3.1 的功能增強,這種方式就不是唯一的方案了.

一、AbstractAnnotationConfigDispatcherServletInitializer

要想替代 web.xml 中的 DispatcherServlet,我們就需要擴展 AbstractAnnotationConfigDispatcherServletInitializer,任意的類擴展它后,都會自動的配置 DispatcherServlet 和 Spring 應用上下文。

注:在Spring 3.0環境中,容器會在類路徑中查找實現 javax.servlet.ServletContainerInitializer 接口的類,如果能發現的話,就會用它來配置 Servlet 容器。Spring提供了這個接口的實現,名為 SpringServletContainerInitializer。這個類反過來會查找實現 WebApplicationInitializer 的類並將配置的任務交給它們來完成。

Spring 3.2 引入了一個便利的WebApplicationInitializer基礎實現,也就是 AbstractAnnotationConfigDispatcherServletInitializer ,如下面的圖片,DispatcherServlet 實現了 AbstractAnnotationConfigDispatcherServletInitializer,因此當部署到Servlet 3.0容器中的時候,容器會自動發現它,並用它來配置Servlet上下文。

 

類中有3個主要方法,getServletMappings, getRootConfigClasses, getServletConfigClasses。

getServletConfigClasses 用來加載配置文件或配置類中所聲明的bean。

getRootConfigClasses 用來加載ContextLoaderListener要加載的bean。

getServletMappings 用來定義請求URL

 

二、WebMvcConfigurerAdapter

要想實現視圖解析、我們還需要擴展WebMvcConfigurerAdapter,使用@EnableWebMvc啟用Spring MVC組件。

 

viewResolver用來配置JSP視圖解析器。

configureDefaultServletHandling配置靜態資源的處理.

 

通過配置configureDefaultServletHandling的enable方法,我們要求DispatcherServlet將對靜態資源的請求轉發到Servlet容器中默認的Servlet上,而不是使用DispatcherServlet本身處理請求。

 

三、Controller

 

這個大家都熟悉也不用細說了。

 

最后奉上整個項目截圖

 

 

示例:

package org.springframework.source.config;
 
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
 
import javax.servlet.*;
 
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
 
//指定開始被servlet處理的url,配置從/開始
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
    
//配置root上下文,如Jpa數據源等等的配置
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] {ApplicationConfig.class, JpaConfig.class, SecurityConfig.class};
    }
    
//配置dispatcher servlet,如果在root config指定了該轉發規則就可以忽略
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] {WebMvcConfig.class};
    }
//配置servlet過濾器
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceEncoding(true);
        DelegatingFilterProxy securityFilterChain = new DelegatingFilterProxy("springSecurityFilterChain");
        return new Filter[] {characterEncodingFilter, securityFilterChain};
    }
//當registerDispatcherServlet完成時自定義registration
    @Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration) {
        registration.setInitParameter("defaultHtmlEscape", "true");
        registration.setInitParameter("spring.profiles.active", "default");
    }
}

=======================================================

AbstractAnnotationConfigDispatcherServletInitializer 剖析

在Servlet 3.0環境中,容器會在類路徑中查找實現 javax.servlet.ServletContainerInitializer 接口的類,如果能發現的話,就會用它來配置Servlet容器。

Spring提供了這個接口的實現,名為 SpringServletContainerInitializer,這個類反過來又會查找實現 WebApplicationInitializer 的類並將配置的任務交給它們來完成。Spring 3.2 引入了一個便利的 WebApplicationInitializer 基礎實現,也就是 AbstractAnnotationConfigDispatcherServletInitializer。因為我們的
MyWebAppInitializer 擴展了 AbstractAnnotationConfigDispatcherServletInitializer,當然也就實現了 WebApplicationInitializer,因此當部署到Servlet 3.0 容器中的時候,容器會自動發現它,並用它來配置 Servlet上下文。

盡管它的名字很長,但是 AbstractAnnotationConfigDispatcherServletInitializer 使用起來很簡便。它僅要求我們重寫其中的三個方法,其他的方法是否重寫則根據你的具體需求而定。

第一個方法是getServletMappings(),它會將一個或多個路徑映射到 DispatcherServlet 上。在本例中,它映射的是“/”,這表示它會是應用的默認Servlet。它會處理進入應用的所有請求。

為了理解其他的兩個方法,我們首先要理解 DispatcherServlet 和一個 Servlet 監聽器,也就是 ContextLoaderListene 的關系。

兩個應用上下文之間的故事:

當 DispatcherServlet 啟動的時候,它會創建 Spring應用上下文,並加載配置文件或配置類中所聲明的bean。在 MyWebAppInitializer 的 getServletConfigClasses() 方法中,我們要求 DispatcherServlet 加載應用上下文時,使用定義在 WebConfig配置類(使用Java配置)中的bean。但是在Spring Web 應用中,通常還會有另外一個應用上下文。另外的這個應用上下文是由 ContextLoaderListener 創建的。

我們希望 DispatcherServlet 加載包含Web組件的bean,如控制器、視圖解析器以及處理器映射,而 ContextLoaderListener 要加載應用中的其他bean。這些bean通常是驅動應用后端的中間層和數據層組件。

實際上,AbstractAnnotationConfigDispatcherServletInitializer 會同時創建 DispatcherServlet 和 ContextLoaderListener。getServletConfigClasses() 方法返回的帶有@Configuration注解的類將會用來定義 DispatcherServlet 應用上下文中的bean,我們暫且把它記為context1。getRootConfigClasses()方法返回的帶有@Configuration注解的類將會用來配置 ContextLoaderListener 創建的應用上下文中的bean,記為context2。那這兩個上下文的關系是什么呢?答案是,context1會把context2設置為parent,這樣,當context1中的bean需要使用到context2中的bean時就可以在其中直接獲取,比如當我們把一個service層的bean注入到controller中時。

在本例中,根配置定義在RootConfig中,DispatcherServlet 的配置聲明在WebConfig中。稍后我們將會看到這兩個類的內容。

需要注意的是,通過 AbstractAnnotationConfigDispatcherServletInitializer 來配置 DispatcherServlet 是傳統web.xml方式的替代方案。如果你願意的話,可以同時包含 web.xml和 AbstractAnnotationConfigDispatcherServletInitializer,但這其實並沒有必要。

如果按照這種方式配置 DispatcherServlet,而不是使用web.xml的話,那唯一問題在於它只能部署到支持 Servlet 3.0的服務器中才能正常工作,如 Tomcat 7或更高版本。如果你還沒有使用支持 Servlet 3.0的服務器,那么在 AbstractAnnotationConfigDispatcherServletInitializer 子類中配置 DispatcherServlet 的方法就不適合你了。你別無選擇,只能使用web.xml了。
-----------------------------------
https://blog.51cto.com/u_9587581/2398187

 

=======================================================


REF

https://blog.51cto.com/u_9587581/2398187

https://baijiahao.baidu.com/s?id=1633224433148237378&wfr=spider&for=pc

https://blog.csdn.net/renchenglin118/article/details/93207031

https://blog.csdn.net/u013571243/article/details/44565289

https://blog.csdn.net/classicer/article/details/50753019


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM