0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

SpringBoot自動(dòng)裝配原理分析

jf_78858299 ? 來源:Java學(xué)習(xí)錄 ? 作者:Java學(xué)習(xí)錄 ? 2023-04-07 10:41 ? 次閱讀

我們知道,在使用SpringBoot的時(shí)候,我們只需要如下方式即可直接啟動(dòng)一個(gè)Web程序:

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

和我們之前使用普通Spring時(shí)繁瑣的配置相比簡直不要太方便,那么你知道SpringBoot實(shí)現(xiàn)這些的原理么

首先我們看到類上方包含了一個(gè)@SpringBootApplication注解

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class?[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class?[] scanBasePackageClasses() default {};
}

這個(gè)注解上邊包含的東西還是比較多的,咱們先看一下兩個(gè)簡單的熱熱身

@ComponentScan 注解

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

這個(gè)注解咱們都是比較熟悉的,無非就是自動(dòng)掃描并加載符合條件的Bean到容器中,這個(gè)注解會默認(rèn)掃描聲明類所在的包開始掃描,例如:

cn.shiyujun.Demo類上標(biāo)注了@ComponentScan 注解,則cn.shiyujun.controller、cn.shiyujun.service等等包下的類都可以被掃描到

這個(gè)注解一共包含以下幾個(gè)屬性:

basePackages:指定多個(gè)包名進(jìn)行掃描
basePackageClasses:對指定的類和接口所屬的包進(jìn)行掃
excludeFilters:指定不掃描的過濾器
includeFilters:指定掃描的過濾器
lazyInit:是否對注冊掃描的bean設(shè)置為懶加載
nameGenerator:為掃描到的bean自動(dòng)命名
resourcePattern:控制可用于掃描的類文件
scopedProxy:指定代理是否應(yīng)該被掃描
scopeResolver:指定掃描bean的范圍
useDefaultFilters:是否開啟對@Component@Repository,@Service@Controller的類進(jìn)行檢測

@SpringBootConfiguration注解

這個(gè)注解更簡單了,它只是對Configuration注解的一個(gè)封裝而已

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

EnableAutoConfiguration注解

這個(gè)注解可是重頭戲了,SpringBoot號稱的約定大于配置,也就是本文的重點(diǎn)自動(dòng)裝配的原理就在這里了

@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class?[] exclude() default {};

    String[] excludeName() default {};
}

簡單概括一下,這個(gè)注解存在的意義就是:利用@Import注解,將所有符合自動(dòng)裝配條件的bean注入到IOC容器中,關(guān)于@Import注解原理這里就不再闡述。

進(jìn)入類AutoConfigurationImportSelector,觀察其selectImports方法,這個(gè)方法執(zhí)行完畢后,Spring會把這個(gè)方法返回的類的全限定名數(shù)組里的所有的類都注入到IOC容器中

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List

觀察上方代碼:

  1. 第一行if時(shí)會首先判斷當(dāng)前系統(tǒng)是否禁用了自動(dòng)裝配的功能,判斷的代碼如下:
protected boolean isEnabled(AnnotationMetadata metadata) {
       return this.getClass() == AutoConfigurationImportSelector.class ? (Boolean)this.getEnvironment().getProperty("spring.boot.enableautoconfiguration", Boolean.class, true) : true;
   }
  1. 如果當(dāng)前系統(tǒng)禁用了自動(dòng)裝配的功能則會返回如下這個(gè)空的數(shù)組,后續(xù)也就無法注入bean了
private static final String[] NO_IMPORTS = new String[0];
  1. 此時(shí)如果沒有禁用自動(dòng)裝配則進(jìn)入else分枝,第一步操作首先會去加載所有Spring預(yù)先定義的配置條件信息,這些配置信息在org.springframework.boot.autoconfigure包下的META-INF/spring-autoconfigure-metadata.properties文件中
  2. 這些配置條件主要含義大致是這樣的:如果你要自動(dòng)裝配某個(gè)類的話,你覺得先存在哪些類或者哪些配置文件等等條件,這些條件的判斷主要是利用了@ConditionalXXX注解。
  3. 這個(gè)文件里的內(nèi)容格式是這樣的:
org.springframework.boot.actuate.autoconfigure.web.servlet.WebMvcEndpointChildContextConfiguration.ConditionalOnClass=org.springframework.web.servlet.DispatcherServlet
org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration.ConditionalOnClass=javax.sql.DataSource,io.micrometer.core.instrument.MeterRegistry
org.springframework.boot.actuate.autoconfigure.flyway.FlywayEndpointAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
  1. 具體的加載代碼就不列出了,無法就是個(gè)讀取配置文件

  2. 這里放個(gè)加載之后的結(jié)果圖:

    圖片

  3. 獲取@EnableAutoConfiguration注解上的exclude、excludeName屬性,這兩個(gè)屬性的作用都是排除一些類的

  4. 這里又是關(guān)鍵的一步,可以看到剛才圖片中spring-autoconfigure-metadata.properties文件的上方存在一個(gè)文件spring.factories,這個(gè)文件可就不止存在于org.springframework.boot.autoconfigure包里了,所有的包里都有可能存在這個(gè)文件,所以這一步是加載整個(gè)項(xiàng)目所有的spring.factories文件。這個(gè)文件的格式是這樣的

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\org.springframework.boot.actuate.autoconfigure.amqp.RabbitHealthIndicatorAutoConfiguration,\\org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration,\\org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration

這里存在一個(gè)知識點(diǎn),SpringBoot中的star就是依靠這個(gè)文件完成的,假如我們需要自定義一個(gè)SpringBoot的Star,就可以在我們的項(xiàng)目的META-INF文件夾下新建一個(gè)spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.shiyujun.TestAutoConfiguration

這樣當(dāng)別的項(xiàng)目依賴我們的項(xiàng)目時(shí)就會自動(dòng)把我們的TestAutoConfiguration類注入到Spring容器中

  1. 刪除重復(fù)的自動(dòng)配置類
  2. 下面三行就是去除我們指定排除的配置類
  3. 接著這一行的邏輯稍微復(fù)雜一些,主要就是根據(jù)加載的配置條件信息來判斷各個(gè)配置類上的@ConditionalXXX系列注解是否滿足需求
  4. 最后就是發(fā)布自動(dòng)裝配完成事件,然后返回所有能夠自動(dòng)裝配的類的全限定名

到了這里我們已經(jīng)把SpringBoot自動(dòng)裝配的原理搞清楚了,但是總感覺差點(diǎn)什么,那我們從這些自動(dòng)裝配的類里面挑一個(gè)我們比較熟悉的關(guān)于Servlet的類來看看咋回事吧:

@Configuration
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
public class ServletEndpointManagementContextConfiguration {
    public ServletEndpointManagementContextConfiguration() {
    }

    @Bean
    public ExposeExcludePropertyEndpointFilter

自上而下觀察整個(gè)類的代碼,你會發(fā)現(xiàn)這些自動(dòng)裝配的套路都是一樣的

  1. 如果當(dāng)前是Servlet環(huán)境則裝配這個(gè)bean
  2. 當(dāng)存在類ResourceConfig以及不存在類DispatcherServlet時(shí)裝配JerseyServletEndpointManagementContextConfiguration
  3. 當(dāng)存在DispatcherServlet類時(shí)裝配WebMvcServletEndpointManagementContextConfiguration
  4. 接下來如果還有面試官問你,你會了么?
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • Web
    Web
    +關(guān)注

    關(guān)注

    2

    文章

    1267

    瀏覽量

    69601
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2973

    瀏覽量

    104932
  • spring
    +關(guān)注

    關(guān)注

    0

    文章

    340

    瀏覽量

    14364
  • SpringBoot
    +關(guān)注

    關(guān)注

    0

    文章

    174

    瀏覽量

    189
收藏 人收藏

    評論

    相關(guān)推薦

    SpringBoot知識總結(jié)

    SpringBoot干貨學(xué)習(xí)總結(jié)
    發(fā)表于 08-01 10:40

    怎么學(xué)習(xí)SpringBoot

    SpringBoot學(xué)習(xí)之路(X5)- 整合JPA
    發(fā)表于 06-10 14:52

    怎樣去使用springboot

    怎樣去使用springboot呢?學(xué)習(xí)springboot需要懂得哪些?
    發(fā)表于 10-25 07:13

    自動(dòng)裝配線的類型與應(yīng)用場景

    在制造業(yè),根據(jù)制造業(yè)和工藝的不同,加工自動(dòng)化裝配線有多種類型,如自動(dòng)加工裝配線、自動(dòng)裝置裝配線、自動(dòng)
    發(fā)表于 06-28 14:24

    關(guān)于自動(dòng)裝配線的設(shè)計(jì)

    自動(dòng)裝配線的設(shè)計(jì)總體目標(biāo)是用小量的職工完成大的勞動(dòng)生產(chǎn)。因?yàn)槭止ぶ谱?b class='flag-5'>自動(dòng)裝配線的設(shè)計(jì)因人有所不同的,這就直接影晌到輸送管道運(yùn)作的實(shí)際效果和工作效率,最主要制造商選用了機(jī)器
    發(fā)表于 03-31 11:27 ?1838次閱讀

    自動(dòng)裝配線有哪些設(shè)計(jì)

    自動(dòng)裝配線輸送帶的實(shí)際操作中,裝配頭對裝配件釋放的力務(wù)必證實(shí)配件的恰當(dāng)聯(lián)接。自動(dòng)裝配線有哪些設(shè)
    發(fā)表于 08-10 14:37 ?1101次閱讀

    Jenkins+docker+springboot一鍵自動(dòng)部署項(xiàng)目

    本文章實(shí)現(xiàn)最簡單全面的Jenkins+docker+springboot 一鍵自動(dòng)部署項(xiàng)目,步驟齊全,少走坑路。
    的頭像 發(fā)表于 09-14 09:30 ?1623次閱讀

    Spring和Springboot的擴(kuò)展接口總結(jié)

    Spring的核心思想就是容器,當(dāng)容器refresh的時(shí)候,外部看上去風(fēng)平浪靜,其實(shí)內(nèi)部則是一片驚濤駭浪,汪洋一片。Springboot更是封裝了Spring,遵循約定大于配置,加上自動(dòng)裝配的機(jī)制。很多時(shí)候我們只要引用了一個(gè)依賴
    的頭像 發(fā)表于 10-13 10:17 ?951次閱讀

    初學(xué)者必看的SpringBoo自動(dòng)裝配原理1

    學(xué)習(xí)SpringBoot,絕對避不開自動(dòng)裝配這個(gè)概念,這也是SpringBoot的關(guān)鍵之一 本人也是SpringBoot的初學(xué)者,下面
    的頭像 發(fā)表于 04-07 11:03 ?664次閱讀
    初學(xué)者必看的SpringBoo<b class='flag-5'>自動(dòng)</b><b class='flag-5'>裝配</b>原理1

    初學(xué)者必看的SpringBoo自動(dòng)裝配原理2

    學(xué)習(xí)SpringBoot,絕對避不開自動(dòng)裝配這個(gè)概念,這也是SpringBoot的關(guān)鍵之一 本人也是SpringBoot的初學(xué)者,下面
    的頭像 發(fā)表于 04-07 11:03 ?589次閱讀

    初學(xué)者必看的SpringBoo自動(dòng)裝配原理3

    學(xué)習(xí)SpringBoot,絕對避不開自動(dòng)裝配這個(gè)概念,這也是SpringBoot的關(guān)鍵之一 本人也是SpringBoot的初學(xué)者,下面
    的頭像 發(fā)表于 04-07 11:03 ?590次閱讀
    初學(xué)者必看的SpringBoo<b class='flag-5'>自動(dòng)</b><b class='flag-5'>裝配</b>原理3

    初學(xué)者必看的SpringBoo自動(dòng)裝配原理4

    學(xué)習(xí)SpringBoot,絕對避不開自動(dòng)裝配這個(gè)概念,這也是SpringBoot的關(guān)鍵之一 本人也是SpringBoot的初學(xué)者,下面
    的頭像 發(fā)表于 04-07 11:03 ?676次閱讀
    初學(xué)者必看的SpringBoo<b class='flag-5'>自動(dòng)</b><b class='flag-5'>裝配</b>原理4

    深入了解SpringBoot自動(dòng)配置原理

    通過這篇文章我們來深入了解SpringBoot自動(dòng)配置原理,并分析SpringBoot是如何神不知,鬼不覺的幫我們做了那么多的事情,讓我們只需要關(guān)心業(yè)務(wù)邏輯開發(fā)就可以了。
    的頭像 發(fā)表于 04-07 11:22 ?1016次閱讀
    深入了解<b class='flag-5'>SpringBoot</b>的<b class='flag-5'>自動(dòng)</b>配置原理

    什么是 SpringBoot

    本文從為什么要有 `SpringBoot`,以及 `SpringBoot` 到底方便在哪里開始入手,逐步分析了 `SpringBoot` 自動(dòng)
    的頭像 發(fā)表于 04-07 11:28 ?1340次閱讀
    什么是 <b class='flag-5'>SpringBoot</b>?

    springboot自動(dòng)裝配原理簡述

    Spring Boot是針對Spring框架的一種快速開發(fā)工具,它通過自動(dòng)裝配(Auto-Configuration)機(jī)制簡化了Spring應(yīng)用程序的配置和部署。本文將詳細(xì)介紹Spring Boot
    的頭像 發(fā)表于 12-03 14:57 ?1775次閱讀