1. 程式人生 > >【原始碼解析】自動配置的這些細節都不知道,別說你會 springboot

【原始碼解析】自動配置的這些細節都不知道,別說你會 springboot

spring-boot 相對於 spring,很重要的一個特點就是自動配置,使約定大於配置思想成功落地。xxx-spring-boot-starter 一系列引導器能夠開箱即用,或者只需要很少的配置(對於初學人員)就是因為已做了預設的自動配置。

自動配置在一開始就初始化了一些配置,同時提供修改配置的入口。

整體結構

spring-boot-autoconfigure 包是 spring-boot-starter 中一個非常重要的包,其中提供了自動配置功能,還對常用依賴,設定了預設配置。

依賴

其依賴的包有三種:

  • 基礎包:spring-boot
  • 可選功能依賴包:提供預設配置的常用依賴包,實際使用時由使用者提供
  • 測試包

可選功能依賴包有 spring-data-redis、validator、thymeleaf、websocket 等等。下面會選幾個作為示例具體講解。

原理

@EnableAutoConfiguration

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
  /**
   *  當此名對應屬性為 true 時,才開啟自動配置
   */
  String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
  
  /**
   *  需要排除的類(通常當此類在類路徑下時使用)
   */
  Class<?>[] exclude() default {};

  /**
   *  需要排除的類名(當此類不在類路徑下時使用)
   */
  String[] excludeName() default {};
}

@AutoConfigurationPackage

將使用此註解的類所屬於的包註冊成 spring bean。
此 spring bean 的 beanName 為 AutoConfigurationPackages,
beanClass 為 BasePackages。

AutoConfigurationImportSelector

自動配置選擇器,選擇哪些類自動配置。

selectImports

核心方法:String[] selectImports(AnnotationMetadata annotationMetadata) ,此方法返回需要自動配置的全類名陣列。
需要自動配置的類滿足以下條件:

  1. META-INF/spring.factories 中 key 為 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的類
  2. @EnableAutoConfiguration 註解中 exclude 、 excludeName 屬性代表的類, 配置中 spring.autoconfigure.exclude 中設定的類(若類路徑中存在,但是步驟 1 不存在,則拋異常)
  3. 滿足包含三種註解的條件:OnBeanCondition(如:ConditionalOnBean、ConditionalOnMissingBean) 、OnClassCondition (如:ConditionalOnClass、ConditionalOnMissingClass)、OnWebApplicationCondition(如:ConditionalOnWebApplication、ConditionalOnNotWebApplication)

最後,會啟用 AutoConfigurationImportEvent 事件。

getImportGroup 與 DeferredImportSelector.Group

對來自不同 ImportSelector 的結果進行分組

自動配置的順序

  • AutoConfigurationSorter
  • @AutoConfigureOrder
  • @AutoConfigureBefore
  • @AutoConfigureAfter

AutoConfigurationSorter 是具體控制排序的邏輯
@AutoConfigureOrder@Order 的 Auto-configuration 特定變體,因此需要制定自定配置的順序時,可以用 @AutoConfigureOrder 。控制應用配置類的絕對順序
@AutoConfigureBefore@AutoConfigureAfter 控制應用配置類的相對順序。

具體培訓順序如下:

  1. 根據類名按照字母表遞增排序
  2. 根據 @AutoConfigureOrder value 值(預設:0)遞增排序
  3. 根據 @AutoConfigureBefore@AutoConfigureAfter 調整排序

那麼 @Order 還能控制自動配置類的順序嗎?

@SpringBootApplication

2.1.8.RELEASE 版本中,此註解的組合註解如下:

// 省略不需關心的註解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

已有原來的 @Configuration 改為 @SpringBootConfiguration,其意義如下:

  • 相當於是 @Configuration 類
  • 使用該註解的類提供 Spring Boot 應用。
    一個應用只能包含一個 @SpringBootConfiguration 類,通常使用 @SpringBootApplication 就可以了

AbstractDependsOnBeanFactoryPostProcessor

此類實現 BeanFactoryPostProcessor,會在 spring-boot 啟動過程中在合適的時機執行
繼承此類,通過構造器動態決定指定型別的 bean 應該依賴於哪些 bean。

BackgroundPreinitializer

此類實現 ApplicationListener<SpringApplicationEvent>
此類功能為:在耗時任務的後臺執行緒中觸發早期初始化,如:
ValidationInitializerMessageConverterInitializerJacksonInitializerCharsetInitializerConversionServiceInitializerMBeanFactoryInitializer

@ImportAutoConfiguration

匯入自動配置類。從原始碼來看,都是測試時用於自動配置。使用此類的註解,也在 META-INF/spring.factories 中配置,示例如下:

@ImportAutoConfiguration
public @interface AutoConfigureDataJpa {}
org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureDataJpa=\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

因此使用註解 AutoConfigureDataJpa 就相當於匯入了 JpaRepositoriesAutoConfiguration、DataSourceAutoConfiguration 等類。

使用如下:

@BootstrapWith(DataJpaTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(DataJpaTypeExcludeFilter.class)
@Transactional
@AutoConfigureCache
@AutoConfigureDataJpa
@AutoConfigureTestDatabase
@AutoConfigureTestEntityManager
@ImportAutoConfiguration
public @interface DataJpaTest {
  // ...
}
@RunWith(SpringRunner.class)
@DataJpaTest
@TestPropertySource(properties = "spring.jpa.hibernate.use-new-id-generator-mappings=false")
public class DataJpaTestIntegrationTests {

    @Autowired
    private TestEntityManager entities;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ExampleRepository repository;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testEntityManager() {
        ExampleEntity entity = this.entities.persist(new ExampleEntity("spring", "123"));
        this.entities.flush();
        Object id = this.entities.getId(entity);
        ExampleEntity found = this.entities.find(ExampleEntity.class, id);
        assertThat(found.getName()).isEqualTo("spring");
    }
    
    // ...

對常用工具的支援

以上原理是提供自動配置的基石,但實際在使用的時候,很多內容不需要任何(或極少量)配置就能直接使用,一方面是各 xxx-spring-boot-starter 中包含了 spring-boot-autoconfigure 並寫了自動配置邏輯,一方面,是 spring-boot 官方在 spring-boot-autoconfigure 包中已經直接支援了。

示例:gson 自動配置

支援有如下類:

  • GsonProperties
  • GsonBuilderCustomizer
  • GsonAutoConfiguration

GsonProperties 類獲取 Gson 的配置屬性

@ConfigurationProperties(prefix = "spring.gson")
public class GsonProperties {
  private Boolean generateNonExecutableJson;
  private Boolean excludeFieldsWithoutExposeAnnotation;
  private Boolean serializeNulls;
  private String dateFormat;
  // ...
}
@FunctionalInterface
public interface GsonBuilderCustomizer {
    /**
     * 自定義 GsonBuilder
     */
    void customize(GsonBuilder gsonBuilder);
}

GsonAutoConfiguration 中使用 GsonProperties 和 GsonBuilderCustomizer(內部類中實現)

@Configuration
@ConditionalOnClass(Gson.class)
@EnableConfigurationProperties(GsonProperties.class)
public class GsonAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public GsonBuilder gsonBuilder(List<GsonBuilderCustomizer> customizers) {
        GsonBuilder builder = new GsonBuilder();
        customizers.forEach((c) -> c.customize(builder));
        return builder;
    }

    @Bean
    @ConditionalOnMissingBean
    public Gson gson(GsonBuilder gsonBuilder) {
        return gsonBuilder.create();
    }

    @Bean
    public StandardGsonBuilderCustomizer standardGsonBuilderCustomizer(GsonProperties gsonProperties) {
        return new StandardGsonBuilderCustomizer(gsonProperties);
    }

    static final class StandardGsonBuilderCustomizer implements GsonBuilderCustomizer, Ordered {

        private final GsonProperties properties;

        StandardGsonBuilderCustomizer(GsonProperties properties) {
            this.properties = properties;
        }

        @Override
        public int getOrder() {
            return 0;
        }

        @Override
        public void customize(GsonBuilder builder) {
         // ...
        }

公眾號:逸飛兮(專注於 Java 領域知識的深入學習,從原始碼到原理,系統有序的學習)

相關推薦

原始碼解析自動配置這些細節知道別說 springboot

spring-boot 相對於 spring,很重要的一個特點就是自動配置,使約定大於配置思想成功落地。xxx-spring-boot-starter 一系列引導器能夠開箱即用,或者只需要很少的配置(對於初學人員)就是因為已做了預設的自動配置。 自動配置在一開始就初始化了一些配置,同時提供修改配置的入口。 整

影象語義分割:從頭開始訓練deeplab v2系列之一原始碼解析

好記性不如爛筆頭, 最近用Deeplab v2跑的影象分割,現記錄如下。 官方原始碼地址如下:https://bitbucket.org/aquariusjay/deeplab-public-ver2/overview 但是此原始碼只是為deeplab網路

原始碼解析憑什麼?spring boot 一個 jar 就能開發 web 專案

問題 為什麼開發web專案,spring-boot-starter-web 一個jar就搞定了?這個jar做了什麼? 通過 spring-boot 工程可以看到所有開箱即用的的引導模組 spring-boot-starter-xxx 都在 spring-boot-starters 子模組中,且所有的 sp

原始碼分享簡訊驗證碼如何對接 WordPressv4.0簡訊外掛

對接簡訊的時候發現一家簡訊公司,有些不錯的簡訊驗證碼的外掛,對接起來挺方便的,有需求的可以看一下。http://www.ihuyi.com/外掛說明本外掛系互億無線針對Wordpress開發,請按以下說明進行安裝,外掛內的所有檔案均為對原檔案的修改,如果你的系統經過二次開發,安裝本外掛之前,請仔細核對修改。

絕地求生—— AI挖掘‘雞王’的技術報告把把吃雞

絕地求生這個電子競技遊戲已經風靡全球。此款遊戲有超過5000萬份出售,是第五個最暢銷的遊戲,並有數百萬活躍的月度玩家。100名玩家被空手扔到一個島上,隨著遊戲區不斷縮小,玩家必須探索,清除,並消滅其他玩家,直到只有一個人或一個隊活到最後,這就是玩家經常說的“吃雞了”。不過

這些知道怎麼去阿里!

本次收錄了一些面試中經常會遇到的經典面試題以及自己面試過程中遇到的一些問題,並且都給出了我在網上收集的答案。馬上就要過春節了,開年就是嶄新的一年,相信很多的前端開發者會有一些跳槽的悸動,通過對本篇知識的整理以及經驗的總結,希望能幫到更多的前端面試者。(如有錯誤或更好的答案,歡迎指正,水平

Android原始碼解析View.post()到底幹了啥

本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出 emmm,大夥都知道,子執行緒是不能進行 UI 操作的,或者很多場景下,一些操作需要延遲執行,這些都可以通過 Handler 來解決。但說實話,實在是太懶了,總感覺寫 Handler 太麻煩了,一不小心又很容

Flume原始碼分析flume中sink到hdfs檔案系統頻繁產生檔案檔案滾動配置起作用?

本人在測試hdfs的sink,發現sink端的檔案滾動配置項起不到任何作用,配置如下: a1.sinks.k1.type=hdfs a1.sinks.k1.channel=c1 a1.sinks.k1.hdfs.useLocalTimeStamp=true a1.sink

藍芽檔案傳輸之obex層之上的分析Android原始碼解析

 在上節中我們仔細分析了藍芽檔案傳輸過程中涉及到的UI介面,最終定格在藍芽裝置掃描的介面,我們只要選擇自己想要傳輸的藍芽裝置就可以進行藍芽檔案的傳輸了。那就是這樣一個簡單的裝置選擇的點選會引發哪些

Android深入解析Manifest配置檔案解析(上)(英文版)

<action> 語法規則: <action android:name="string"/> 描述 : Adds an action to an intentfilter. An elementmust contain one or more

Netty原始碼解析NioEventLoop

上一篇部落格【Netty原始碼學習】EventLoopGroup中我們介紹了EventLoopGroup,實際說來EventLoopGroup是EventLoop的一個集合,EventLoop是一個單執行緒的執行緒池,其介面和類實現關係如下:接下來我們主要介紹實現類NioEv

WinForm 天貓2013雙11自動搶紅包原始碼下載

1. 正確獲取紅包流程 2. 軟體介紹 2.1 效果圖: 2.2 功能介紹 2.2.1 賬號登入 頁面開始時,會載入這個網站:https://login.taobao.com/member/login.jhtml?redirect_url=http%3A%2F%2F1111.tmal

cocos2d-x 原始碼解析幀動畫

前言 幀動畫是以序列幀輪放的方式來表現一個動畫,就像膠片電影一樣,一張張畫面進行切換,當切換的間隔足夠小時,人眼就看不出中間的間隔,而是一個流暢的視訊。cocos2d-x 中的幀動畫涉及到三個類 AnimationFrame,Animation 和 Anima

Android 原始碼解析淺談DecorView與ViewRootImpl

一、前言 對於Android開發者而言,View無疑是開發中經常接觸的,包括它的事件分發機制、測量、佈局、繪製流程等。如果要自定義一個View,那麼應該對以上流程有所瞭解、研究。在深入接觸View的測量、佈局、繪製這三個流程之前,我們從Activity入手,看看從Act

Andorid原始碼解析View.post() 到底幹了啥

本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出 emmm,大夥都知道,子執行緒是不能進行 UI 操作的,或者很多場景下,一些操作需要延遲執行,這些都可以通過 Handler 來解決。但說實話,實在是太懶了,總感覺寫 Hand

Spring實戰----Spring配置檔案的解析

一、背景知識Spring的核心的核心就是bean的配置及管理,至Spring最新發布的版本4.3.2已經有三種方式可以配置bean:1)在XML中進行顯示配置2)在Java中進行顯示配置3)隱式的bean發現機制和自動裝配上述三種配置不展開說明,而且目前用的較多的是第3種(當

Spring原始碼解析—— 結合SpringMVC過程理解IOC容器初始化之註解部分探究

前面的文章寫了xml中直接配置bean進行IOC的過程解析,接下來會針對註解進行IOC容器初始化的過程解析 因為會與之前的內容存在部分重疊,因此會針對相同的部分簡略帶過,針對不同的部分做重點說明:   一、Xml的配置和程式碼中的註解配置: applicationContext.xml配置新

Spring原始碼解析—— 簡單工廠模式的BeanFactory的超簡版實現

 一、什麼是簡單工廠模式 設計模式的核心是“分工”,通過分工將物件與職責劃分的更細化,進而提升系統設計的可擴充套件性,使其更容易維護。   開閉原則:對擴充套件開放,對修改關閉;要增加一個新的處理邏輯,可以開一個新的類,不要在老的上面修改 依賴倒轉原則:依賴關係從具體轉向抽象,也就是說:A

Spring原始碼解析FactoryBean-工廠方法模式的實現及使用

一、工廠方法模式中的三種模式的特點 工廠模式中的三種模式,分別是:簡單工廠模式、工廠方法模式、抽象工廠模式,三種分別是什麼,以及適合場景是什麼? (1)簡單工廠模式:一個抽象介面對應一個產品介面,特定產品實現這個介面,針對不同產品都可以在同一個工廠中生產,同一個工廠生產產品可以通過多種方式,單生產方法(通

Spring原始碼解析—— 策略模式在Spring中的應用

一、         什麼是策略模式 策略模式的定義/含義:策略本身就是為了實現某一個目標而採取的一種工作方式,因此只要能夠達成目標,則採取哪一種策略都可以;因此多種實際的策略之間是相互平行的。 注意:策略模式與模板模式是不同