1. 程式人生 > 程式設計 >SpringBoot Application註解原理及程式碼詳解

SpringBoot Application註解原理及程式碼詳解

1、SpringBoot 啟動main()

@SpringBootApplication
public class TomcatdebugApplication {

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

}

1.1 @SpringBootApplication 註解,其實主要是@ComponentScan,@EnableAutoConfiguration,@SpringBootConfiguration三個註解

SpringBoot Application註解原理及程式碼詳解

@ComponentScan 註解:

spring裡有四大註解:@Service,@Repository,@Component,@Controller用來定義一個bean.@ComponentScan註解就是用來自動掃描被這些註解標識的類,最終生成ioc容器裡的bean.

可以通過設定@ComponentScan basePackages,includeFilters,excludeFilters屬性來動態確定自動掃描範圍,型別已經不掃描的型別.

 預設情況下:它掃描所有型別,並且掃描範圍是@ComponentScan註解所在配置類包及子包的類

@SpringBootConfiguration 註解:

@SpringBootConfiguration繼承自@Configuration,二者功能也一致,標註當前類是配置類,
並會將當前類內宣告的一個或多個以@Bean註解標記的方法的例項納入到spring容器中,並且例項名就是方法名。

demo 說明:

(1) 注入spring ioc bean

@SpringBootConfiguration
public class Config {
  @Bean
  public Map createMap(){
    Map map = new HashMap();
    map.put("username","gxz");
    map.put("age",27);
    return map;
  }
}

(2)呼叫:

public static void main( String[] args )
  {
    //方式1 獲取context
    ConfigurableApplicationContext context = SpringApplication.run(App.class,args);
    context.getBean(Runnable.class).run();
    context.getBean("createMap");  //注意這裡直接獲取到這個方法bean
    int age = (int) map.get("age");
    System.out.println("age=="+age);
//方式2. 使用@Autowired註解,應用bean 
// @Autowired// Map createMap
}

@EnableAutoConfiguration 註解

@EnableAutoConfiguration作用:從classpath中搜索所有的META-INF/spring.factories配置檔案,然後將其中key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的value載入到spring容器中。

SpringBoot Application註解原理及程式碼詳解

上圖分析原始碼可知: @EnableAutoConfiguration = @Import + @AutoConfigurationPackage

@AutoConfigurationPackage:主要作用是自動配置包

@Import: Spring底層註解@Import,給容器中匯入一個元件;匯入的元件由AutoConfigurationPackages.Registrar.class將主配置類(@SpringBootApplication標註的類)的所在包以及下面所有子包裡面的所有元件掃描到Spring容器。

AutoConfigurationImportSelector的作用是匯入哪些元件的選擇器。將所有需要匯入的元件以全類名的方式返回,這些元件就會被新增到容器中;也會給容器匯入非常多的自動配置類(xxxAutoConfiguration),就是給容器中匯入這個場景需要的所有元件,並配置好這些元件。

  有了自動配置類,免去了我們手動編寫配置注入功能元件等的工作

具體工作流程圖:

SpringBoot Application註解原理及程式碼詳解

@EnableAutoConfiguration載入過程

 自動配置主要由AutoConfigurationImportSelector實現的,我們主要從這個類開始講起。AutoConfigurationImportSelector是@EnableAutoConfiguration“@Import”的DeferredImportSelector實現類,由於DeferredImportSelector作為ImportSelector的子介面,所以元件自動配置邏輯均在selectImports(AnnotationMetadata)方法中實現

原始碼分析:  

AutoConfigurationImportSelector.java

根據以上程式碼分析自動配置載入過程主要分為以下幾個步驟:

1.判斷是否開啟自動配置

2.從META-INF/spring-autoconfigure-metadata.properties檔案中載入屬性配置

3.獲取所有的配置列表

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    //1.是否開啟自動配置,預設開啟
  if (!this.isEnabled(annotationMetadata)) {
    return NO_IMPORTS;
  } else {
    try {
        //2.從META-INF/spring-autoconfigure-metadata.properties檔案中載入屬性配置(有一些有預設值),獲取註解資訊

      AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
       
       //3.獲取所有的配置列表
      AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
      List<String> configurations = this.getCandidateConfigurations(annotationMetadata,attributes);
      configurations = this.removeDuplicates(configurations);
      configurations = this.sort(configurations,autoConfigurationMetadata);
      Set<String> exclusions = this.getExclusions(annotationMetadata,attributes);
      this.checkExcludedClasses(configurations,exclusions);
      configurations.removeAll(exclusions);
      configurations = this.filter(configurations,autoConfigurationMetadata);
      this.fireAutoConfigurationImportEvents(configurations,exclusions);
      return (String[])configurations.toArray(new String[configurations.size()]);
    } catch (IOException var6) {
      throw new IllegalStateException(var6);
    }
  }
}

1.是否開啟自動配置,預設開啟

 protected boolean isEnabled(AnnotationMetadata metadata) {
    return true;
  }

2.從META-INF/spring-autoconfigure-metadata.properties檔案中載入屬性配置

protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";

  private AutoConfigurationMetadataLoader() {
  }

  public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
    return loadMetadata(classLoader,"META-INF/spring-autoconfigure-metadata.properties");
  }
  static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader,String path) {
    try {
      Enumeration<URL> urls = classLoader != null ? classLoader.getResources(path) : ClassLoader.getSystemResources(path);
      Properties properties = new Properties();
      while(urls.hasMoreElements()) {
        properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource((URL)urls.nextElement())));
      }
      return loadMetadata(properties);
    } catch (IOException var4) {
      throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]",var4);
    }
  }

3、獲取所有的配置列表

protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
    String name = this.getAnnotationClass().getName();
    AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name,true));
    Assert.notNull(attributes,"No auto-configuration attributes found. Is " + metadata.getClassName() + " annotated with " + ClassUtils.getShortName(name) + "?");
    return attributes;
  }

總結:

springboot底層實現自動配置的步驟:

1.springboot應用啟動

2.@SpringBootApplication起作用

3.@EnableAutoConfiguration

4.@AutoConfigurationPackage:這個組合註解主要是@Import(AutoConfigurationPackages.Registrar.class),它通過將Registrar類匯入到容器中,而Registrar類作用是掃描主配置類同級目錄以及子包,並將相應的元件匯入到springboot建立管理的容器中

5.@Import(AutoConfigurationImportSelector.class):它通過將AutoConfigurationImportSelector類匯入到容器中,AutoConfigurationImportSelector類作用是通過selectImports方法實現將配置類資訊交給SpringFactory載入器進行一系列的容器建立過程,具體實現可檢視上面的原始碼

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。