SpringBoot原理講解


一.問題的引入

首先我們來看一個最簡單的例子。

我們先創建一個SpringBoot的工程,如何創建一個SpringBoot工程就不說了,不會請自行解決。然后寫一個controller類,通過請求路徑,返回HelloWorld在瀏覽器頁面上顯示。

        

  上面兩張圖就是程序的一個整體的結構和運行的結果,那么問題來了,SpringBoot程序中沒有任何配置,不像Spring框架,寫一大堆配置信息在xml文件中,那么程序是怎么將我們這里的Controller類掃描到spring容器中的呢?

二.原理講解。

首先第一點,我們來看一下SpringBoot的啟動類,

package com.example.demo;



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;



@SpringBootApplication

public class DemoApplication {



    public static void main(String[] args) {

        //啟動SpringBoot應用

        SpringApplication.run(DemoApplication.class, args);

    }

}

  

其中,我們看到一個注解@SpringBootApplication,SpringBoot應用標注在某個類上說明這個類是SpringBoot的主配置類,SpringBoot就應該運行這個類的main方法來啟動SpringBoot應用;

然后我們點進去看看這個注解到底包含了什么,

@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 {      

  

其中我們需要重點關注的就是@SpringBootConfiguration、@EnableAutoConfiguration

下面我們逐個來講解:

@SpringBootConfiguration這個注解顧名思義,標注在某個類上,這個類就是SpringBoot的配置類,我們再點進去看看。

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Configuration

  

 

原來這個注解是底層是Spring中的注解@Configuration,而@Configuration注解底層就是一個@Component,代表一個容器。

 

 

SpringBoot的精髓是在@EnableAutoConfiguration這個注解上,根據名字,我們可以知道這是一個自動配置類,也就是能夠實現一些自動配置的功能,那么具體是配置了什么東西呢?

我們再點進去看看

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage

@Import(AutoConfigurationImportSelector.class)

  

我們看見了和這個注解有關聯的重要的兩個注解@AutoConfigurationPackage,@Import(AutoConfigurationImportSelector.class),也是分別給大家講解一下。

1.@AutoConfigurationPackage

@AutoConfigurationPackage:這是一個自動配置的包,我們來看下在這個程序中是配置了哪個包,點進來

@Import(AutoConfigurationPackages.Registrar.class)

  

 

再點到Register,我們看到在大概123行的位置,有一段代碼。

@Override

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {

   register(registry, new PackageImport(metadata).getPackageName());

}

  

我們看到這個方法器中一個參數metadata,代表注解的元信息,然后我們通過這個注解的元信息來獲這個包名,我們在這打個斷點,debug運行,可以看見一些元信息的基本內容,最主要我們要知道是導入了哪個包,我們選中new PackageImport(metadata).getPackageName(),右鍵計算一下

發現導入的包就是我們項目的根目錄,假如我們新建一個包叫com.controller,在里面寫一個controller類,大家可以運行的試一下是否能成功呢。

 

2.@Import(AutoConfigurationImportSelector.class)

     @Import(AutoConfigurationImportSelector.class):這個注解代表的是一個自動配置的選擇器,那么要導入哪些組件的選擇器呢?

我們點進去,看到非常重要的一段。

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);

}

  

 這里我們獲得到了一個configurations 的list集合,我們打個斷點看看這個集合中到底給我們裝了些什么東西。

我們發現這個configurations 里面裝配了124個自動配置類,原來我們沒有配置的一些信息,都通過SpringBoot的自動配置類給我配置好了。

那么我還想知道這些類SpringBoot程序給我們放到哪了呢,我們看到getCandidateConfigurations(annotationMetadata, attributes);

點進去,我們看到:

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass()

  

 

那么再點進去我們看看到底加載的工廠名稱是啥,

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());

         }

      }

   }

  

我們看到其中類加載器給我們獲取了資源,我們點進去,

點了這么多次,終於找到我們想要的答案了!!!

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

  

 

原來這些自動配置類都在類路徑下的"META-INF/spring.factories"

還有下面的autoconfigure包中的內容,我們也看看

這里面我們所有所用到的配置類全部由SpringBoot給我們配置了,所以我們知道SpringBoot表面上是零配置的,其實底層都給我們封裝好了,也是方便我們程序員進行開發。

那么有些人肯定又有疑惑,SpringBoot怎么知道給我們自動配置哪些類呢?

欲知后事如何,請關注一下作者,純手打碼字不易,也是希望和大家多多交流,一起學習,謝謝!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM