1. 程式人生 > >Spring Boot自動裝配原理原始碼分析

Spring Boot自動裝配原理原始碼分析

1.環境準備

使用IDEA Spring Initializr快速建立一個Spring Boot專案

新增一個Controller類

@RestController
public class HelloController {

    @RequestMapping("hello")
    public String hello() {
        return "hello";
    }
}

主配置類如下

@SpringBootApplication
public class SpringbootQuickstartApplication {

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

}

2.註解分析

Spring Boot規定,專案的主配置類必須放在最外層包,也就是說,所有的類都必須放在主配置類的同級包或者子包裡,這麼做的用意是什麼?我們點開@SpringBootApplication註解慢慢分析(下面程式碼中省略元註解)...

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

@SpringBootApplication內部標註了三個註解:

  • @SpringBootConfiguration

    進入原始碼中可以看見,@SpringBootConfiguration其實就是Spring中的@Configuration,用於標註配置類

    @Configuration
    public @interface SpringBootConfiguration {
  • @ComponentScan

    這個註解也是Spring中的,它用來將指定包下需要裝配的元件註冊到容器中

  • @EnableAutoConfiguration

    接下來才是今天的重頭戲,Spring Boot自動配置的主角!

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

3.自動裝配的主角

​ 進入@EnableAutoConfiguration原始碼你會發現這個註解中標註了兩個註解@AutoConfigurationPackage@Import

(1)、@AutoConfigurationPackage

點進該註解

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

在點進Register,這是一個靜態內部類

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

  @Override
  public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
      register(registry, new PackageImport(metadata).getPackageName());
   }

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

我們在第一個方法處打一個斷點debug一下,發現new PackageImport(metadata).getPackageName()的結果其實就是一個包名,這時我們很容易的可以想到,這個包就是Spring Boot主配置類所在的包

再看一眼metadata,果然,就是主配置類

因此,這個註解的作用就是將主配置類所在的包作為自動配置包進行管理

(2)、@Import(AutoConfigurationImportSelector.class)

@Import的作用就是匯入一個類到IOC容器,我們先來看一下匯入的這個類:自動配置匯入選擇器

原始碼裡有一個方法selectImports,選擇匯入

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
   }
   AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
         .loadMetadata(this.beanClassLoader);
   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
         annotationMetadata);
   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

在點進getAutoConfigurationEntry,獲取自動配置類

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
      AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
   configurations = removeDuplicates(configurations);
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   checkExcludedClasses(configurations, exclusions);
   configurations.removeAll(exclusions);
   configurations = filter(configurations, autoConfigurationMetadata);
   fireAutoConfigurationImportEvents(configurations, exclusions);
   return new AutoConfigurationEntry(configurations, exclusions);
}

getCandidateConfigurations方法處打一個斷點,發現configurations的結果是所有的xxxAtuoConfiguration類,一共124個,請記住這個數字。

那麼這些自動配置類是如何獲取的呢,從哪裡獲取的呢?

我們繼續點進getCandidateConfigurations,獲取候選的配置

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations =                     
        SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
         getBeanClassLoader());
   Assert.notEmpty(configurations, "... ...");
   return configurations;
}

繼續點,loadFactoryNames,載入工廠名,方法所在類中有一個常量FACTORIES_RESOURCE_LOCATION,看程式碼可以清晰的看到,這方法載入classpath下的所有jar包的META-INF/spring.factories檔案,結果用一個HashMap儲存

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }
        try {
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }

開啟spring-boot-autoconfigure-2.2.4.RELEASE.jar/META-INF/spring.factories,檔案部分類容如下,你可以點進去看看第22~145行,確實是124個全類名

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration
... ...

4.類的載入時機

載入了這麼多類我們又不一定全都用得到,設計師肯定會想辦法讓類在我們需要的時候才生效,我們隨便點進一個類,可以看到一片飄紅,因為我們並沒有引入RabbitMQ相關依賴,再看一個註解ConditionalOnClass,意思就是存在某個指定的類才生效,類似的註解還有很多,都是@ConditionaOn xxx,在一定條件下類才會生效。

由於引入了web模組,WebMvcAutoConfiguration正常顯示

相關推薦

Spring Boot自動裝配原理原始碼分析

1.環境準備 使用IDEA Spring Initializr快速建立一個Spring Boot專案 新增一個Controller類 @RestController public class HelloController { @RequestMapping("hello"

Spring Boot 自動裝配原理

## Spring Boot 自動裝配原理 Spring Boot 在啟動之前還有一系列的準備工作,比如:推斷 web 應用型別,設定初始化器,設定監聽器,啟動各種監聽器,準備環境,建立 applicationContext,準備 context 上下文物件,在 prepareContext 的時候,將 m

spring boot學習二:Spring Boot自動裝配分析與實戰

Web application conditions:@ConditionalOnWebApplication和@ConditionalOnNotWebApplication,當專案是web專案,或者不是web專案的條件註解 SpEL expression conditions:@Conditional

spring boot 自動裝配原理

工作原理 illegal 而已 cli you kaa part site 參考 參考: https://blog.csdn.net/Dongguabai/article/details/80865599。如有侵權,請聯系本人刪除! 入口: import org.s

Spring 原始碼(十)Spring Aware自動裝配原理

在初始化Bean的initializeBean方法中執行invokeAwareMethods方法 通後置處理器ApplicationContextAwareProcessor來實現的,它實現了BeanPostProcessor介面 invokeAwareMethods 我們在初始化Bean的時候,為了保

Spring Boot自動配置原理(轉)

腳本 bst file ade hazelcast oauth dbd 參考 b-s 第3章 Spring Boot自動配置原理3.1 SpringBoot的核心組件模塊首先,我們來簡單統計一下SpringBoot核心工程的源碼java文件數量:我們

Spring boot 自動配置原理

ssa fix 構造 color llb sel elastics 控制 enc 1、自動配置原理: 1)、SpringBoot啟動的時候加載主配置類,開啟了自動配置功能 ==@EnableAutoConfiguration== 2)、@EnableAutoConfigur

4、Spring Boot 自動配置原理

add adp over 生成 修改 more servlet func details 1.4 Spring Boot 自動配置原理 簡介 spring boot自動配置功能可以根據不同情況來決定spring配置應該用哪個,不應該用哪個,舉個例子: Spring的J

Spring Boot自動配置原理

@SpringBootApplication Spring Boot啟動的時候載入主配置類 @SpringBootApplication public class HelloSpringBootApplication { public static void

【SpringBoot】spring-boot-自動配置原理

思考:配置檔案到底能寫什麼?怎麼寫?自動配置原理; 1.自動配置原理 springboot自動配置主演通過@EnableConfiguration,@Conditional,@EnableConfigurationProperties或者@ConfiguraionProp

Spring Boot 自動裝配

底層裝配技術 Spring 模式註解裝配 Spring @Enable 模組裝配 Spring 條件裝配裝配 Spring 工廠載入機制 實現類: SpringFactoriesLoader 配置資源: META-INF/spring.factories

Spring Boot自動配置原理、實戰

Spring Boot自動配置原理 Spring Boot的自動配置註解是@EnableAutoConfiguration, 從上面的@Import的類可以找到下面自動載入自動配置的對映。 org.springframework.core.io.sup

Spring Boot 自動配置原理application.properties

自動配置呢 Spring Boot spring-boot-autoconfigure 依賴做了很多預設的配置項,即應用預設值。這種模式叫做 “自動配置”。Spring Boot 自動配置會根據新增的依賴,自動載入依賴相關的配置屬性並啟動依賴。例如預設用的內嵌

我理解的spring boot自動配置原理

個人筆記,不喜勿噴! 功力不夠,寫不出來,:( ----------------------------------------------- 精髓: sring boot 啟動時會載入大量的自動配置類; 看看我們需要的功能有沒有Spring Boot預設寫好的自動

Spring Boot自動配置原理與實踐(一)

前言   Spring Boot眾所周知是為了簡化Spring的配置,省去XML的複雜化配置(雖然Spring官方推薦也使用Java配置)採用Java+Annotation方式配置。如下幾個問題是我剛開始接觸Spring Boot的時候經常遇到的一些疑問,現在總結出來希望能幫助到更多的人理解Spring B

Spring Boot自動裝配

前言 一些朋友問我怎麼讀原始碼,這篇文章結合我看原始碼時候一些思路給大家聊聊,我主要從這三個方向出發: 確定目標,這個目標要是一個具體,不要一上來我要看懂Spring,這是不可能的,目標要這麼來定,比如看懂Spring Boot的自動裝配、Spring IOC XML載入流程等等,儘量小,能夠快速搞定的,

Spring Boot 自動裝配流程

# Spring Boot 自動裝配流程 本文以 mybatis-spring-boot-starter 為例簡單分析 Spring Boot 的自動裝配流程。 ## Spring Boot 發現自動配置類 這裡說的自動配置類指的是在 `META-INF/spring.factories` 檔案中宣告的

Spring Boot自動裝配原理

        Spring Boot的“開箱即用”的原則,使得企業應用開發中各種場景的Spring開發更加快速,更加高效,由於配置大量減少,開發效率相得益彰。   啟動原理:SpringBoot專案會有一個啟動類,這個啟動類會使用@SpringBootApplicatio

Spring Boot 自動配置 原始碼分析

Spring Boot 最大的特點(亮點)就是自動配置 AutoConfiguration 下面,先說一下 @EnableAutoConfiguration ,然後再看原始碼,到底自動配置是怎麼配置的 1.  @EnableAutoConfiguration @Spring

Spring Boot實戰與原理分析視頻課程

spring boot 視頻課程 實戰與原理分析 1、Spring Boot概述與課程概要介紹2、Spring4 快速入門3、Spring4 擴展分析(一)4、Spring4 擴展分析(二)5、Spring Boot 快速入門6、Spring Boot 配置分析(一)7、Spring Boot 配