詳解@EnableWebMvc


最近看了《Spring in Action》的開頭,就被Spring注解開發(完全不寫web.xml)驚嘆了,也第一次知道了@EnableWebMvc是SpringMVC的注解

@EnableWebMvc注解

@EnableWebMvc的javaDoc注釋有點長。  從下圖得到的幾個信息: href="mailto:1.@EnableWebMvc">1.@EnableWebMvc沒有任何屬性,只是@Import了一個類叫DelegatingWebMvcConfiguration 

2. 注釋中說明:將@EnableWebMvc添加給@Configuration類來導入SpringMvc的配置;3.自定義MVC配置,實現接口WebMvcConfigurer或更可能繼承WebMvcConfigurerAdapter,並且使用@EnableWebMvc;

4.如果還想要自定義配置,移除@EnableWebMvc,並且繼承WebMvcConfigurationSupport或DelegatingWebMvcConfiguration。

5.@EnableWebMvc出現自Spring3.1的版本

image

 


@EnableWebMvc的注釋文檔說的很詳細,先記錄第一點,@Import的類是干啥的!

@Import的多種用法看我這篇文檔:Spring @Import .   @Import導入了一個類DelegatingWebMvcConfiguration,這個類標注了@Configuration類,這個類下方法上標注了@Bean的都會納入Spring容器管理。

DelegatingWebMvcConfiguration類如下,但是類里面搜索卻沒有@Bean標注! 在其父類WebMvcConfigurationSupport里面搜索到了19個@Bean.

這19個@Bean基本上和<mvc:annotation-driven/>實現的功能無差,甚至提供了一種很便捷的方式擴展<mvc:annotation-driven/>

image

 

舉兩個栗子,說明下:1. <mvc:annotation-driven/> @ResponseBody 返回String中文亂碼  Spring @ResponseBody String中文亂碼

image

@EnableWebMvc同樣存在這個問題,默認字符集為ISO-8859-1,解決方案:繼承WebMvcConfigurerAdapter,重寫extendMessageConverters方法!

image

 

栗子2:比如需要添加攔截器,原先寫法可能是<mvc:interceptors></mvc:interceptors>這種形式添加,現在不用XML,方式就是這樣:

在繼承WebMvcConfigurerAdapter基礎上,重寫addInterceptor方法。

image

 


 

@EnableWebMvc可擴展的結構

圖片可以從processOn拷貝,RequestMappingHandlerMapping地址:https://www.processon.com/view/5c9d8480e4b035b243ba651b

                                      RequestMappingHandlerAdapter地址:https://www.processon.com/view/5c9d86cee4b034408de5663d  紅框代表可繼承擴展WebMvcConfigurerAdapter等擴展的方法。

image

 

 

想到為什么繼承WebMvcConfigurerAdapter或者實現WebMvcConfigurer,就能夠在@EnableWebMvc繼承上擴展呢?

@EnableWebMvc導入的是DelegatingWebMvcConfiguration類,和WebMvcConfigurer完全沒有聯系啊?

 

image

說明:DelegatingWebMvcConfiguration類,有這樣一個屬性WebMvcConfigurerComposite,維護着WebMvcConfigurer的集合,有點類似組合模式。

        初始化DelegatingWebMvcConfiguration時如果發現了WebMvcConfigurer的實現類,就注入到WebMvcConfigurerComposite中,這樣就把我們實現了WebMvcConfigurer的類和@EnableWebMvc聯系到一起了,

就可以在<mvc:annotation-driven/>基礎上擴展.

       這里很神奇,在我理解中Spring沒法自動判斷兩個Bean作為集合注入的啊! 這里起作用的就是required=false  少了這句話就拋出異常!

 

 


 

@EnableWebMvc默認是沒有靜態資源放行的,比如.css  .js文件默認  也會被 dispatchServelt   / 形式的攔截到

原來在web.xml文件中可以這樣配置,靜態資源后綴為.js  .css不攔截

       <servlet-mapping>
		<servlet-name>default</servlet-name>
		<url-pattern>*.html</url-pattern>
		<url-pattern>*.htm</url-pattern>
		<url-pattern>*.css</url-pattern>
		<url-pattern>*.js</url-pattern>
	</servlet-mapping>

 

在沒有web.xml的文件中解決方案:繼承WebMvcConfigurerAdapter,並且重寫configureDefaultServletHandling方法,即可達到和上面一樣的效果,就可以訪問 .css .js等文件!

image

 

原理解析:如果這篇博客前面看過了,直接看到WebMvcConfigurationSupport,@Bean注冊了一個bean  defaultServletHandlerMapping,最終configureDefaultServletHandling會制定我們上面的方法。

image

DefaultServletHandlerConfigurer只是個配置類,Bean實際返回的是hanlderMapping!=null?handlerMapping:new EmptyHandlerMapping();  EmptyHandlerMapping不對請求做任何處理,而configurer的getHandlerMapping方法如下: handler不為空,就會返回一個SimpleUrlHandlerMapping,而configurer.enable()方法等價於configurer.enable(null),就是初始化handler的。總的來說就是,configurer.enable()方法就是注冊了一個SimpleUrlHandlerMapping對象,handler就是DefaultServletHttpRequestHandler. 

image

image

 

 

DefaultServletHttpRequestHandler如何處理靜態資源請求?

通過獲取 服務器默認的servlet進行轉發,因為/** 會匹配所有的URI,所以SimpleUrlHandlerMapping必須放在RequestMappingHandlerMapping之后;核心方式就是servletContext.getNamedDispatcher(“default”).forward(request,response);

image

 

總結@EnableWebMvc替我們做了什么?

引入了這樣一個類DelegatingWebMvcConfiguration,通過@Bean注冊了和<mvc:annotation-driven/>一樣的組件,RequestMappingHandlerMapping、RequestMappingHandlerAdatper、HandlerExceptionResolver等等,只要有個Spring管理的bean繼承WebMvcConfigurer或WebMvcConfigurerAdapter,重寫方法即可自定義<mvc:annotation-driven/>.

其實@EnableWebMvc == @Import({DelegatingWebMvcConfiguration.class})


免責聲明!

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



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