SpringBoot——MVC原理

優質博文:IT-BLOG-CN

一、SpringMVC自動配置

SpringMVC auto-configurationSpringBoot自動配置好了SpringMVC。以下是SpringBootSpringMVC的默認配置:[WebMvcAutoConfiguration]
【1】包括ContentNegotiatingViewResolverBeanNameViewResolver如下:

@Bean
@ConditionalOnBean({ViewResolver.class})
@ConditionalOnMissingBean(name = {"viewResolver"},value = {ContentNegotiatingViewResolver.class}
)
//存在于 WebMvcAutoConfiguration.java
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));resolver.setOrder(-2147483648);return resolver;
}//進入ContentNegotiatingViewResolver對象,查找解析視圖的方法resolveViewName()
public View resolveViewName(String viewName, Locale locale) throws Exception {RequestAttributes attrs = RequestContextHolder.getRequestAttributes();Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());if(requestedMediaTypes != null) {//獲取候選的視圖對象List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);//選擇最適合的視圖對象View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);if(bestView != null) {return bestView;}
}//進入上面的getCandidateViews()方法,查看獲取的視圖解析器,發現SpringBoot是將所有的視圖解析器獲取到viewResolvers,挨個遍歷獲取。
private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception {List<View> candidateViews = new ArrayList();Iterator var5 = this.viewResolvers.iterator();while(var5.hasNext()) {

【2】自動配置了ViewResolver(視圖解析器:根據方法的返回值得到視圖對象(View),視圖對象決定如何渲染(轉發?重定向?))
【3】ContentNegotiatingViewResolver:組合所有的視圖解析器的;

//進入ContentNegotiatingViewResolver發現初始化視圖解析器的時候,是從容器中BeanFactoryUtils獲取所有的視圖解析器。
protected void initServletContext(ServletContext servletContext) {Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.getApplicationContext(), ViewResolver.class).values();if(this.viewResolvers == null) {

【4】如何定制:我們可以自己給容器中添加一個視圖解析器;自動的將其組合進來;

 @Bean@ConditionalOnProperty(prefix = "spring.mvc", name = "date‐format")//在文件中配置日期格式化的規則public Formatter<Date> dateFormatter() {        return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化組件            } //舉個栗子如下:
//可以自定義一個視圖解析器,放入容器,springboot就會自動識別,繼承viewreserve
@Bean
public MyView myView(){return new MyView();
}
//需要實現ViewResolver接口
private static class MyView implements ViewResolver{@Overridepublic View resolveViewName(String s, Locale locale) throws Exception {return null;}
}

【5】服務對靜態資源的支持,靜態資源文件夾路徑,webjars等。靜態首頁訪問,自定義favicon.ico 圖標文件的支持。
【6】自動注冊了of Converter,GenericConverter,Formatter beans
?○ Converter:轉換器; public String hello(User user):類型轉換使用ConverterStringint等等。
?○ Formatter 格式化器; 2017.12.17===Date,源碼如下:可以看到格式可以通過spring.mvc.date-format調整。

@Bean
@ConditionalOnProperty(prefix = "spring.mvc",name = {"date-format"}
)
public Formatter<Date> dateFormatter() {return new DateFormatter(this.mvcProperties.getDateFormat());
}

?○ 自己添加的格式化器轉換器,我們只需要放在容器中即可,上面代碼塊有演示。
【7】支持HttpMessageConverters
?○ HttpMessageConverterSpringMVC用來轉換Http請求和響應的;UserJson方式寫出去;
?○ HttpMessageConverters是從容器中確定;獲取所有的HttpMessageConverter
?○ 自己給容器中添加HttpMessageConverter,只需要將自己的組件注冊容器中[@Bean,@Component]
【8】自動注冊MessageCodesResolver,定義錯誤代碼生成規則。自動使用ConfigurableWebBindingInitializer類;

protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {return (ConfigurableWebBindingInitializer)this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
}

它是從容器中獲取ConfigurableWebBindingInitializer的,從而可知,我們可以配置一個ConfigurableWebBindingInitializer來替換默認的(添加到容器),如果沒有配置會初始化一個Web數據綁定器:

//初始化Web數據綁定器,作用就是將請求數據綁定到JavaBean中,參數等,涉及數據轉換等等
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();initializer.setConversionService(this.mvcConversionService());initializer.setValidator(this.mvcValidator());initializer.setMessageCodesResolver(this.getMessageCodesResolver());return initializer;
}

【9】org.springframework.boot.autoconfigure.webweb的所有自動場景;上面能夠得到的主要思想就是:如何修改Springboot的默認配置:
?1)、在自動配置很多組件的時候,先看容器中有木有用戶自己配置的(@Bean,@Component)如果有就是用用戶配置的,如果沒有就是用自動配置的,因為底層使用了@ConditionalOnMiss注解來判斷,容器中是否已經存在此類配置。
?2)、如果有些組件可以配置多個,比如視圖解析器(ViewResolver)將用戶配置的和自己默認的組合起來。

擴展 SpringMVC: 官方解釋:If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

【1】根據我們之前的配置xml來進行擴展:

<mvc:view‐controller path="/hello" view‐name="success"/>
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/hello"/><bean></bean></mvc:interceptor>
</mvc:interceptors>

【2】SpringBoot編寫一個配置類@Configuration,繼承WebMvcConfigurerAdapter類型,不能標注@EnableWebMvc。 繼承抽象類既保留了所有的自動配置,也能用我們擴展的配置;

//使用WebMvcConfigurerAdapter可以來擴展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {// super.addViewControllers(registry);//瀏覽器發送 /yintong 請求來到 success ,視圖映射,當沒有業務邏輯的時候就比較方便registry.addViewController("/yintong").setViewName("success");}
}

原理:
【1】WebMvcAutoConfigurationSpringMVC的自動配置類;
【2】在做其他自動配置時會導入;@Import(EnableWebMvcConfiguration.class)

@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();//從容器中獲取所有的WebMvcConfigurer    @Autowired(required = false)public void setConfigurers(List<WebMvcConfigurer> configurers) {if (!CollectionUtils.isEmpty(configurers)) {this.configurers.addWebMvcConfigurers(configurers);//一個參考實現;將所有的WebMvcConfigurer相關配置都來一起調用;      @Override    public void addViewControllers(ViewControllerRegistry registry) {for (WebMvcConfigurer delegate : this.delegates) {delegate.addViewControllers(registry);}}}
}

【3】容器中所有的WebMvcConfigurer都會一起起作用;
【4】我們的配置類也會被調用;
【5】效果:SpringMVC的自動配置和我們的擴展配置都會起作用;

二、全面接管SpringMVC

讓所有SpringMVC的自動配置都失效。使用我們需要的配置,需要在配置類中添加 @EnableWebMvc即可。非常不推薦,不然使用SpringBoot開發干嘛,哈哈。

//使用WebMvcConfigurerAdapter可以來擴展SpringMVC的功能 
@EnableWebMvc 
@Configuration 
public class MyMvcConfig extends WebMvcConfigurerAdapter {     @Override     public void addViewControllers(ViewControllerRegistry registry) {// super.addViewControllers(registry);         //瀏覽器發送 /atguigu 請求來到 success                 registry.addViewController("/atguigu").setViewName("success");     } 
}

原理: 為什么@EnableWebMvc自動配置就失效了?

【1】@EnableWebMvc的核心組合注解:

@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {

【2】我們打開上面導入的DelegatingWebMvcConfiguration類,會發現其繼承了WebMvcConfigurationSupport

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

【3】我們看下SpringBoot自動配置的文件,發現如下:@ConditionalOnMissingBean(WebMvcConfigurationSupport.class),可知當容器中存在WebMvcConfigurationSupport類時,就不會導入自動配置的類了,第二步導入的就是這個類。

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })        
//容器中沒有這個組件的時候,這個自動配置類才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })        
public class WebMvcAutoConfiguration {

【4】@EnableWebMvcWebMvcConfigurationSupport組件導入進來;
【5】導入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;

結論:SpringBoot中會有非常多的xxxConfigurer幫助我們進行擴展配置。同時,在SpringBoot中也會有很多的xxxCustomizer幫助我們進行定制配置。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/164578.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/164578.shtml
英文地址,請注明出處:http://en.pswp.cn/news/164578.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Keil工程打開發現目標芯片無法選擇解決方案

買了一個開發板&#xff0c;配套有一些底層驅動的例程&#xff0c;打開后發現目標芯片無法選擇&#xff0c;對應的下載Flash FLM文件也無法選擇。從提示框中可以知道所提供的例程是Keil4的例程&#xff0c;我電腦上安裝的Keil版本是Keil版本&#xff0c;估計是這個原因導致工程…

C# 執行Excel VBA宏工具類

寫在前面 在Excel文檔的自動化處理流程中&#xff0c;有部分值需要通過已定義的宏來求解&#xff0c;所以延伸出了用C# 調用Excel中的宏代碼的需求。 首先要從NuGet中引入Microsoft.Office.Interop.Excel 類庫 using Excel Microsoft.Office.Interop.Excel; 代碼實現 /// &l…

HashMap,1.7與1.8的區別,HashMap的擴容方式有哪些

HashMap,1.7與1.8的區別 底層數據結構的區別 JDK 1.8之前&#xff1a; 1&#xff09;JDK1.8 之前HashMap 底層是數組和鏈表結合在一起使用也就是鏈表散列。 2&#xff09;HashMap 通過key 的hashCode 經過擾動函數處理過后得到hash 值&#xff0c;然后通過(n - 1&#xff09…

修改el-radio-group樣式,自定義單選組件

修改el-radio-group樣式,自定義單選組件 自定義組件 MyRadioGroup.vue <template><div class"btnsBox"><el-radio-group v-model"activeIndex" change"handleClick"><el-radio-buttonv-for"(item, index) in list&qu…

CSS3動畫

在CSS3中新增了一個很有意思的東西&#xff0c;那就是動畫&#xff0c;有了動畫我們可以做很多的事情&#xff0c;讓我為大家介紹一下動畫吧&#xff01; 本篇文章關于介紹動畫&#xff0c;利用小球移動為你們介紹一下動畫 默認樣式&#xff1a; <!DOCTYPE html> <ht…

普通話考試相關(一文讀懂)

文章目錄&#xff1a; 一&#xff1a;相關常識 1.考試報名時間 2.報名地方 費用 證件 3.考試流程 4.普通話等級說明 二&#xff1a;題型 三&#xff1a;技巧 1.前三題 2.命題說話 四&#xff1a;普通話考試題庫 1.在線題庫 2.下載題庫 一&#xff1a;相關常識 …

JavaEE(SpringMVC)期末復習

文章目錄 JavaEE期末復習一、單選題&#xff1a; JavaEE期末復習 一、單選題&#xff1a; 1.Spring的核?技術是&#xff08; A &#xff09;&#xff1f; A依賴注入 B.JdbcTmplate C.聲明式事務 D.資源訪問 Spring的核心技術包括依賴注入&#xff08;Dependency Injection&am…

【前端】js通過canvas獲取瀏覽器的唯一指紋可以當做唯一標識

【前端】js通過canvas獲取瀏覽器的唯一指紋可以當做唯一標識 <!DOCTYPE html> <html><head> <meta charset"utf-8" /> <meta name"viewport" content"widthdevice-width" /> <title>JS Bin</title> &…

解決Emmy Lua插件在IDEA或 Reder 沒有代碼提示的問題(設置文件關聯 增加對.lua.txt文件的支持)

目錄 Reder版本2019.x Reder版本2021.1.5x Reder版本2019.x 解決Emmy Lua插件在IDEA或 Reder 沒有代碼提示的問題(設置文件關聯 增加對.lua.txt文件的支持) Reder版本2021.1.5x 解決Emmy Lua插件在IDEA或 Reder 沒有代碼提示的問題(設置文件關聯 增加對.lua.txt文件的支持)…

java游戲制作-王者榮耀游戲

一.準備工作 首先創建一個新的Java項目命名為“王者榮耀”&#xff0c;并在src下創建兩個包分別命名為“com.sxt"、”com.stx.beast",在相應的包中創建所需的類。 創建一個名為“img”的文件夾來儲存所需的圖片素材。 二.代碼呈現 package com.sxt;import javax.sw…

Netty Review - 探索ByteBuf的內部機制

文章目錄 概念ByteBuf VS Java NIO BufferByteBuf實現類HeapByteBuf vs DirectByteBufPooledByteBuf vs UnpooledByteBuf其他 ByteBuf的實現機制 概念 ByteBuf是Netty中用于處理二進制數據的緩沖區 Netty的ByteBuf是一個可用于高效存儲和操作字節數據的數據結構。與傳統的Byt…

跳躍游戲[中等]

優質博文&#xff1a;IT-BLOG-CN 一、題目 給你一個非負整數數組nums&#xff0c;你最初位于數組的第一個下標 。數組中的每個元素代表你在該位置可以跳躍的最大長度。判斷你是否能夠到達最后一個下標&#xff0c;如果可以&#xff0c;返回true&#xff1b;否則&#xff0c;返…

阿里入局鴻蒙!鴻蒙原生應用再添兩員新丁

今日HarmonyOS微博稱&#xff0c;阿里釘釘、螞蟻集團旗下的移動開發平臺mPaaS與華為達成合作&#xff0c;宣布啟動鴻蒙原生應用的開發&#xff01;相關應用將以原生方式適配#HarmonyOS NEXT#系統。 #HarmonyOS#市場或迎來爆發式增長&#xff01; 阿里釘釘 阿里釘釘與華為達成合…

Android 匿名內存深入分析

Android 匿名內存解析 有了binder機制為什么還需要匿名內存來實現IPC呢&#xff1f;我覺得很大的原因就是binder傳輸是有大小限制的&#xff0c;不說應用層的限制。在驅動中binder的傳輸大小被限制在了4M&#xff0c;分享一張圖片可能就超過了這個限制。匿名內存的主要解決思路…

黑馬點評-10實現用戶點贊和點贊排行榜功能

用戶點贊功能 如果用戶只要點贊一次就對數據庫中blog表中的liked字段的值加1就會導致一個用戶無限點贊 PutMapping("/like/{id}") public Result likeBlog(PathVariable("id") Long id) {// 修改點贊數量,update tb_blog set liked liked 1 where id …

編譯器核心技術概覽

編譯技術是一門龐大的學科&#xff0c;我們無法對其做完善的講解。但不同用途的編譯器或編譯技術的難度可能相差很大&#xff0c;對知識的掌握要求也會相差很多。如果你要實現諸如 C、JavaScript 這類通用用途語言&#xff08;general purpose language&#xff09;&#xff0c…

buck降壓電路

一、Buck電路的拓撲結構 Buck是直流轉直流的降壓電路,下面是拓撲結構,作為硬件工程師,這個最好是能夠記下來,了然于胸。 為啥要記下來,自然是因為這個電路太基礎了,并且誰都會用到,更重要的一點,面試可能會考。。。 上圖是個異步buck,同步buck就是將里面的二極管換成M…

3D火山圖繪制教程

一邊學習&#xff0c;一邊總結&#xff0c;一邊分享&#xff01; 本期教程內容 **注&#xff1a;**本教程詳細內容 Volcano3D繪制3D火山圖 一、前言 火山圖是做差異分析中最常用到的圖形&#xff0c;在前面的推文中&#xff0c;我們也推出了好幾期火山圖的繪制教程&#xff0…

Android——資源IDnonFinalResIds和“Attribute value must be constant”錯誤

一、異常描述 通過資源ID引用資源提示錯誤 Attribute value must be constant 二、解決方案 在根目錄下的文件 gradle.properties 中添加如下配置&#xff0c;然后Sync Project android.nonFinalResIdsfalse 三、問題原因 android.nonFinalResIds 是Android開發中一個用于解…

此處不允許使用特性namespace

1.DOCTYPE 后面改成 mapper 2.PUBLIC一行中的Config改為Mapper 3.將下一行config變為小寫的mapper <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.or…