SpringBoot自動配置原理踩身,你真的懂嗎稍浆?

概述

上面博文(SpringBoot簡介與快速搭建)我們簡單的介紹了什么是SpringBoot互艾,以及如何使用SpringBoot试和,但是我們對于SpringBoot的基本原理并沒有介紹,這篇博文我們重點介紹SpringBoot是如何實現(xiàn)的自動配置忘朝。


依賴管理

在我們的pom文件中最核心的依賴就一個:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.4</version>
    <relativePath/>
</parent>

它的父項目依賴灰署,規(guī)定所有依賴的版本信息:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.4.4</version>
</parent>

由此,我們發(fā)現(xiàn)springboot框架幾乎聲明了所有開發(fā)中常用的依賴的版本號局嘁,無需關注版本號,而且實現(xiàn)了自動版本仲裁機制晦墙,當然了我們也可以根據(jù)我們的需要悦昵,替換掉默認的依賴版本。


核心注解@SpringBootApplication

@SpringBootApplication
public class BootApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootApplication.class, args);
    }
}

在上面的啟動類中我們發(fā)現(xiàn)了一個陌生的注解@SpringBootApplication晌畅,這個注解的是什么含義呢但指?我們點進去看一下。

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

其實@SpringBootApplication是上面三個注解的組合體抗楔,我們對這三個注解理解清楚就可以了棋凳,下面逐個進行解釋:


@SpringBootConfiguration

@Configuration
public @interface SpringBootConfiguration {

@Configuration我們并不陌生,它允許在上下文中注冊額外的bean或導入其他配置類连躏,@SpringBootConfiguration其實代表當前類是一個配置類剩岳。


@EnableAutoConfiguration

EnableAutoConfiguration的目的是啟動SpringBoot的自動配置機制。

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

1入热、AutoConfigurationPackage指定默認的包規(guī)則

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

AutoConfigurationPackage注解的作用是將 添加該注解的類所在的package 作為 自動配置package 進行管理拍棕。也就是說當SpringBoot應用啟動時默認會將啟動類所在的package作為自動配置的package。然后使用@Import注解將其注入到ioc容器中勺良。這樣绰播,可以在容器中拿到該路徑。

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
      register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
   }

   @Override
   public Set<Object> determineImports(AnnotationMetadata metadata) {
      return Collections.singleton(new PackageImports(metadata));
   }

}

重點看下registerBeanDefinitions方法尚困。

方法的第二個參數(shù)通過new PackageImport(metadata).getPackageName()方法設置蠢箩。

接著看下PackageImport的構造器方法。

PackageImports(AnnotationMetadata metadata) {
   AnnotationAttributes attributes = AnnotationAttributes
         .fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false));
   List<String> packageNames = new ArrayList<>(Arrays.asList(attributes.getStringArray("basePackages")));
   for (Class<?> basePackageClass : attributes.getClassArray("basePackageClasses")) {
      packageNames.add(basePackageClass.getPackage().getName());
   }
   if (packageNames.isEmpty()) {
      packageNames.add(ClassUtils.getPackageName(metadata.getClassName()));
   }
   this.packageNames = Collections.unmodifiableList(packageNames);
}

ClassUtils.getPackageName(metadata.getClassName())獲取標注@AutoConfigurationPackage注解的類的全限定名。

最后谬泌,利用Registrar給容器中導入一系列組件滔韵,將指定的包下的所有組件導入進來。

2呵萨、@Import(AutoConfigurationImportSelector.class)

使用Import自動導入所有符合自動配置條件的Bean定義并加載到IOC容器

@Override
        public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
            Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
                    () -> String.format("Only %s implementations are supported, got %s",
                            AutoConfigurationImportSelector.class.getSimpleName(),
                            deferredImportSelector.getClass().getName()));
            AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
                    .getAutoConfigurationEntry(annotationMetadata);
            this.autoConfigurationEntries.add(autoConfigurationEntry);
            for (String importClassName : autoConfigurationEntry.getConfigurations()) {
                this.entries.putIfAbsent(importClassName, annotationMetadata);
            }
        }

1奏属、利用getAutoConfigurationEntry(annotationMetadata);給容器中批量導入一些組件
2、調用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)獲取到所有需要導入到容器中的配置類
3潮峦、利用工廠加載 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)囱皿;得到所有的組件
4、從META-INF/spring.factories位置來加載一個文件忱嘹。
默認掃描我們當前系統(tǒng)里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.4.4.RELEASE.jar包里面也有META-INF/spring.factories

在這里插入圖片描述

文件里面寫死了spring-boot一啟動就要給容器中加載的所有配置類spring-boot-autoconfigure-2.4.4.RELEASE.jar/META-INF/spring.factories嘱腥,一共130個自動配置類。

130個場景的所有自動配置拘悦,會在springboot啟動的時候默認全部加載齿兔。xxxxAutoConfiguration會按照條件裝配規(guī)則(@Conditional),最終會按需配置础米。

小結:

SpringBoot為我們的應用程序啟用了三個功能:自動配置分苇,組件掃描,以及能夠在"應用類"上定義額外的配置屁桑。


@ComponentScan

@Component在應用程序所在的軟件包上啟用掃描医寿,指定掃描哪些Spring注解。


ServletWebServerFactoryAutoConfiguration為例

在130個場景有我們比較熟悉兩個組件蘑斧,ServletWebServerFactoryAutoConfiguration和WebMvcAutoConfiguration靖秩,我們以ServletWebServerFactoryAutoConfiguration為例,看一下SpringBoot是如何自動裝配的webServer竖瘾。

在這里插入圖片描述

在注解中我們看到了大量以@Conditional開頭的注解沟突,即條件裝配,滿足Conditional指定的條件捕传,則進行組件注入惠拭。@EnableConfigurationProperties(ServerProperties.class)+@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true),讀取我們在配置文件編寫的屬性乐横,并把它封裝到JavaBean中求橄,以供隨時使用。

此時我們的Tomcat容器已經(jīng)以Bean的形式被注入到了IOC容器中葡公。


如何禁用特定的自動配置類

如果發(fā)現(xiàn)應用中不需要特定自動配置類罐农,則可以使用exclude屬性@SpringBootApplication來禁用它們,如以下示例所示:

import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.jdbc.*;

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
//@SpringBootApplication(excludeName = {"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"})
public class MyApplication {
}

如果該類不在類路徑中催什,則可以使用excludeName注釋的屬性涵亏,并指定完全限定的名稱(全類名字符串)。定義排除項,即可以使用哪個注釋級別也可以使用屬性來定義气筋。


總結

  • SpringBoot預先加載META-INF/spring.factories中所有的自動配置類拆内,xxxxxAutoConfiguration

  • 每個自動配置類按照條件進行生效,默認都會綁定配置文件指定的值宠默。xxxxProperties里面拿麸恍。xxxProperties和配置文件進行了綁定

  • 生效的配置類就會給容器中裝配很多組件,只要容器中有這些組件搀矫,相當于有了這些功能

  • 定制化配置

    • 用戶直接自己@Bean替換底層的組件
    • 用戶根據(jù)這個組件是獲取的配置文件的什么值抹沪,可以自行修改。

EnableAutoConfiguration ---> 掃描xxxxxAutoConfiguration ---> 根據(jù)條件@Conditional裝配組件 --->根據(jù)xxxxProperties加載屬性值 ----> application.properties


作者:程序猿小亮

博主寫作不易瓤球,加個關注唄

求關注融欧、求點贊,加個關注不迷路卦羡,感謝

點贊是對我最大的鼓勵
↓↓↓↓↓↓

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末噪馏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子绿饵,更是在濱河造成了極大的恐慌欠肾,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拟赊,死亡現(xiàn)場離奇詭異董济,居然都是意外死亡,警方通過查閱死者的電腦和手機要门,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來廓啊,“玉大人欢搜,你說我怎么就攤上這事∏绰郑” “怎么了炒瘟?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長第步。 經(jīng)常有香客問我疮装,道長,這世上最難降的妖魔是什么粘都? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任廓推,我火速辦了婚禮,結果婚禮上翩隧,老公的妹妹穿的比我還像新娘樊展。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布专缠。 她就那樣靜靜地躺著雷酪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪涝婉。 梳的紋絲不亂的頭發(fā)上哥力,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音墩弯,去河邊找鬼吩跋。 笑死,一個胖子當著我的面吹牛最住,可吹牛的內容都是我干的钞澳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼涨缚,長吁一口氣:“原來是場噩夢啊……” “哼轧粟!你這毒婦竟也來了?” 一聲冷哼從身側響起脓魏,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤兰吟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后茂翔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體混蔼,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年珊燎,在試婚紗的時候發(fā)現(xiàn)自己被綠了惭嚣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡悔政,死狀恐怖晚吞,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情谋国,我是刑警寧澤槽地,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站芦瘾,受9級特大地震影響纪岁,放射性物質發(fā)生泄漏黔衡。R本人自食惡果不足惜旨椒,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一枯夜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧藐吮,春花似錦溺拱、人聲如沸逃贝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沐扳。三九已至,卻和暖如春句占,著一層夾襖步出監(jiān)牢的瞬間沪摄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工纱烘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留杨拐,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓擂啥,卻偏偏與公主長得像哄陶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哺壶,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內容