最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

springboot自動裝配的源碼與流程圖

 更新時間:2021年08月04日 10:14:00   作者:迷戀著你微笑的人zz  
在日常的開發(fā)過程中Spring Boot自動裝配的特性給我們開發(fā)減少了很多重復(fù)性的工作,這篇文章主要給大家介紹了關(guān)于springboot自動裝配的相關(guān)資料,需要的朋友可以參考下

前言

在使用SpringBoot開發(fā)項目中,遇到一些 XXX-XXX-starter,例如mybatis-plus-boot-starter,這些包總是能夠自動進行配置,
減少了開發(fā)人員配置一些項目配置的時間,讓開發(fā)者擁有更多的時間用于開發(fā)的任務(wù)上面。下面從源碼開始。

正文

SpringBoot版本:2.5.3

  1. 從@SpringBootApplication進入@EnableAutoConfiguration
  2. 然后進入AutoConfigurationImportSelector
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
            @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {}

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {}

進入AutoConfigurationImportSelector,可以發(fā)現(xiàn)該類是ImportSelector接口的實現(xiàn)類,然后直接定位至selectImports方法。

到了這里,其實主動裝配的套路就是@EnableXXX加@Import的套路。這就是一個大概的認知了。

    @Override
   public String[] selectImports(AnnotationMetadata annotationMetadata) {
      if (!isEnabled(annotationMetadata)) {
         return NO_IMPORTS;
      }
      AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
      return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
   }

下面進入getAutoConfigurationEntry方法:

        protected AutoConfigurationEntry getAutoConfigurationEntry(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 = getConfigurationClassFilter().filter(configurations);
            fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationEntry(configurations, exclusions);
        }

詳細的注釋已經(jīng)寫在代碼中的了,這里面最重要的是getCandidateConfigurations方法,其次是下面的過濾排除不需要的配置信息。下面進入getCandidateConfigurations方法。

        protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            // 重要
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                    getBeanClassLoader());
            Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
                    + "are using a custom packaging, make sure that file is correct.");
            return configurations;
        }

        protected Class<?> getSpringFactoriesLoaderFactoryClass() {
              return EnableAutoConfiguration.class;
        }

        protected ClassLoader getBeanClassLoader() {
              return this.beanClassLoader;
        }

這里需要關(guān)注的方法是SpringFactoriesLoader.loadFactoryNames,進入該方法,該方法是一個靜態(tài)方法。

   public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
      ClassLoader classLoaderToUse = classLoader;
      if (classLoaderToUse == null) {
         classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
      }
        // 獲取類名
      String factoryTypeName = factoryType.getName();
      return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
   }

   private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        // 查詢緩存
      Map<String, List<String>> result = cache.get(classLoader);
      if (result != null) {
         return result;
      }
      result = new HashMap<>();
      try {
            // 1. 獲取類加載器能讀取的所有在META-INF目錄下的spring.factories文件
         Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
         while (urls.hasMoreElements()) {
            // 遍歷路徑
            URL url = urls.nextElement();
            UrlResource resource = new UrlResource(url);
                // 將路徑下的文件數(shù)據(jù)讀取為Properties
            Properties properties = PropertiesLoaderUtils.loadProperties(resource);
            // 遍歷Properties
            for (Map.Entry<?, ?> entry : properties.entrySet()) {
               String factoryTypeName = ((String) entry.getKey()).trim();
               String[] factoryImplementationNames =
                     StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
               for (String factoryImplementationName : factoryImplementationNames) {
                  result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                        .add(factoryImplementationName.trim());
               }
            }
         }
         // Replace all lists with unmodifiable lists containing unique elements
            // 用不可修改列表替換
         result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
               .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
            // 加入緩存
         cache.put(classLoader, result);
      }
      catch (IOException ex) {
         throw new IllegalArgumentException("Unable to load factories from location [" +
               FACTORIES_RESOURCE_LOCATION + "]", ex);
      }
      return result;
   }
  1. loadSpringFactories方法就是加載并讀取所傳入的類加載器能讀取的所有spring.factories文件,并將讀取的數(shù)據(jù)最終轉(zhuǎn)換為Map<String, List>類型的數(shù)據(jù),然后存入本地緩存。
  2. loadFactoryNames方法就是通過傳入factoryType(也就是calss.name)來獲取數(shù)據(jù),并不是獲取所有的數(shù)據(jù)。所以這里會有很多地方會用到。
  3. @EnableAutoConfiguration是取的文件中的org.springframework.boot.autoconfigure.EnableAutoConfiguration,所以一般自定義starter的自動配置文件都是在這個key后面。例如:org.springframework.boot.autoconfigure.EnableAutoConfiguration= a.b.c.d.XXX;

至此,源碼就差不多完成了,其實從源碼上來看其實也不難。

大概流程圖如下:

最后

說了這么多源碼,也畫了流程圖。這里面最重要的就是SpringFactoriesLoader,從這個類名就可以看出來,是專門處理factories文件的,這個類只提供了兩個靜態(tài)方法,而EnableAutoConfiguration只是取了其中的EnableAutoConfiguration下的數(shù)據(jù),那么其它的數(shù)據(jù)呢,不會用到嗎?肯定不會的,所以spring在很多地方會用到這個類,后面看spring源碼的時候在來看吧,這里先標記一下。

還有就是,SpringFactoriesLoader和JDK的SPI也是差不多的一個思想。下一篇就來看看JDK的SPI

到此這篇關(guān)于springboot自動裝配的源碼與流程圖的文章就介紹到這了,更多相關(guān)springboot自動裝配內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java二叉樹的幾種遍歷遞歸與非遞歸實現(xiàn)代碼

    java二叉樹的幾種遍歷遞歸與非遞歸實現(xiàn)代碼

    這篇文章主要介紹了java二叉樹的幾種遍歷遞歸與非遞歸實現(xiàn)代碼,需要的朋友可以參考下
    2020-12-12
  • Springboot集成RabbitMQ報錯及解決

    Springboot集成RabbitMQ報錯及解決

    這篇文章主要介紹了Springboot集成RabbitMQ報錯及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • IDEA啟動報錯Internal?error.?Please?refer?to?https://jb.gg/ide/critical-startup-errors解決辦法

    IDEA啟動報錯Internal?error.?Please?refer?to?https://jb.gg/i

    這篇文章主要介紹了IDEA啟動報錯Internal?error.?Please?refer?to?https://jb.gg/ide/critical-startup-errors解決辦法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • java 簡單的計算器程序?qū)嵗a

    java 簡單的計算器程序?qū)嵗a

    這篇文章主要介紹了java 簡單的計算器程序?qū)嵗a的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • 基于SpringMVC @RequestMapping的參數(shù)和用法

    基于SpringMVC @RequestMapping的參數(shù)和用法

    這篇文章主要介紹了SpringMVC @RequestMapping的參數(shù)和用法解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 深入解析Java的設(shè)計模式編程中建造者模式的運用

    深入解析Java的設(shè)計模式編程中建造者模式的運用

    這篇文章主要介紹了深入解析Java的設(shè)計模式編程中建造者模式的運用,同時文中也介紹了建造者模式與工廠模式的區(qū)別,需要的朋友可以參考下
    2016-02-02
  • Java可重入鎖的實現(xiàn)原理與應(yīng)用場景

    Java可重入鎖的實現(xiàn)原理與應(yīng)用場景

    今天小編就為大家分享一篇關(guān)于Java可重入鎖的實現(xiàn)原理與應(yīng)用場景,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Java有效處理異常的三個原則

    Java有效處理異常的三個原則

    Java中異常提供了一種識別及響應(yīng)錯誤情況的一致性機制,有效地異常處理能使程序更加健壯、易于調(diào)試。那么這篇文章總結(jié)了Java有效處理異常的三個原則,有需要的朋友們可以參考借鑒。
    2016-09-09
  • IDEA遠程連接HBase及其Java API實戰(zhàn)詳解

    IDEA遠程連接HBase及其Java API實戰(zhàn)詳解

    這篇文章主要介紹了IDEA遠程連接HBase及其Java API實戰(zhàn)詳解,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • SpringBoot使用Redis實現(xiàn)消息隊列的方法小結(jié)

    SpringBoot使用Redis實現(xiàn)消息隊列的方法小結(jié)

    在應(yīng)用中把Redis當成消息隊列來使用已經(jīng)屢見不鮮了,我想主要原因是當代應(yīng)用十有八九都會用到 Redis,因此不用再引入其他消息隊列系統(tǒng),而且Redis提供了好幾種實現(xiàn)消息隊列的方法,用起來也簡單,本文給大家介紹了SpringBoot使用Redis實現(xiàn)消息隊列的方法小結(jié)
    2024-04-04

最新評論

页游| 永吉县| 义乌市| 若羌县| 乾安县| 含山县| 宁都县| 民权县| 惠州市| 崇阳县| 枝江市| 登封市| 新余市| 宜城市| 建湖县| 达拉特旗| 白城市| 二连浩特市| 安龙县| 米脂县| 漾濞| 宜兰市| 防城港市| 阳春市| 五台县| 吴堡县| 南城县| 永和县| 海口市| 天镇县| 江孜县| 武宁县| 彭水| 新化县| 沧州市| 临洮县| 上蔡县| 中超| 湘潭县| 育儿| 桐乡市|