SpringBoot-運行原理(四)

1.自動配置

(1).pom.xml

在pom文件中java

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

在它的父工程中,有他的核心依賴web

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
</parent>

點進去,咱們發現,springboot自動幫咱們管理了依賴spring

這只是其中的一小部分,咱們在寫或者引入有一些依賴的時候,不須要指定版本springboot

(2).啓動器

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

springboot-boot-starter:就是spring-boot的場景啓動器app

這裏的 spring-boot-starter-web 幫咱們導入了web模塊正常運行所依賴的組件;spring-boot

SpringBoot將全部的功能場景都抽取出來,作成一個個的starter (啓動器),只須要在項目中引入這些starter便可,全部相關的依賴都會導入進來 , 咱們要用什麼功能就導入什麼樣的場景啓動器便可 ;spa

(3).主程序(啓動類)

package com.bao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Springboot01HelloworldApplication {

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

}

@SpringBootApplication 來標註一個主程序類 , 說明這是一個Spring Boot應用命令行

run方法: 將Spring應用啓動起來code

咱們看一下@SpringBootApplication註解xml

//四個標準註解
@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 :SpringBoot的配置類 ,標註在某個類上,表示這是一個SpringBoot的配置類
  • @EnableAutoConfiguration : 啓用自動配置,這個註解是讓Spring Boot配置可以如此簡化的關鍵性註解
  • @ComponentScan : 掃描當前主啓動類同級的包

點擊@SpringBootConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
    @AliasFor(annotation = Configuration.class)
    boolean proxyBeanMethods() default true;

}

@Configuration : 表明是一個spring配置類

點擊Configuration發現有一個@Component,表明是一個spring組件

點擊@EnableAutoConfiguration

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

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    /**
     * Exclude specific auto-configuration classes such that they will never be applied.
     * @return the classes to exclude
     */
    Class<?>[] exclude() default {};

    /**
     * Exclude specific auto-configuration class names such that they will never be
     * applied.
     * @return the class names to exclude
     * @since 1.3.0
     */
    String[] excludeName() default {};

}

主要是 :

  • @AutoConfigurationPackage
  • @Import(AutoConfigurationImportSelector.class)兩個

AutoConfigurationPackage(自動配置包)

註解的做用是將 添加該註解的類所在的package 做爲 自動配置package 進行管理。

主要是Registrar.class

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.context.annotation.Import;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//導入選擇器
@Import(AutoConfigurationPackages(自動配置註冊包).Registrar.class)
public @interface AutoConfigurationPackage {
}

@import :Spring底層註解@import , 給容器中導入一個組件 ,導入的組件由 {Registrar.class} 將主配置類 【即@SpringBootApplication標註的類】的所在包及包下面全部子包裏面的全部組件掃描到Spring容器 ;

@Import(AutoConfigurationImportSelector.class)

  • Import他的做用是給容器導入組件
  • AutoConfigurationImportSelector.class: (自動配置導入選擇器)導入哪些組件的選擇器

它將全部須要導入的組件以全類名的方式返回 , 這些組件就會被添加到容器中 ;

它會給容器中導入很是多的自動配置類 (xxxAutoConfiguration), 就是給容器中導入這個場景須要的全部組件 , 並配置好這些組件 ;

有了自動配置類 , 免去了咱們手動編寫配置注入功能組件等的工做;

點擊AutoConfigurationImportSelector

有這樣的一個方法

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:獲取候選配置

//獲取全部配置
List<String> configurations = 
    getCandidateConfigurations(annotationMetadata, attributes);

點擊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;
}
//返回用來加載配置候選的類。標註了EnableAutoConfiguration註解的類(主啓動類)
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}

而在@SpringBootApplication註解中標註了@EnableAutoConfiguration

因此就是啓動類下的全部資源被導入

在這裏咱們發現了META-INF/spring.factories文件.這個就是自動配置的核心文件

咱們去springboot的jar中尋找該文件

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

點擊loadFactoryNames方法

loadFactoryNames : 獲取全部的加載配置

返回的loadSpringFactories

從這些資源中便利了全部的nextElement元素(也能夠理解爲自動配置)

遍歷完成後封裝成Properties,供咱們使用

//全部資源加載到配置類中
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
獲取項目資源:classLoader.getResources(FACTORIES_RESOURCE_LOCATION) 
獲取系統資源:ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION))

點擊FACTORIES_RESOURCE_LOCATION,獲取靜態資源的位置

META-INF/spring.factories獲取配置文件

須要導入對應的starter才能起做用

例如

因爲@ConditionalOnClass的存在,會判斷條件成立,纔會加載配置這個類

@ConditionalOnXXX若是這裏面的條件都知足,纔會生效

(4).結論

SpringBoot全部的自動配置都在啓動類中掃描並加載,也就是spring.factories文件

全部的自動配置類都在這個文件中,可是並不必定生效,要判斷條件是否成立,只要導入對應的start,就會有對應的啓動器,有了啓動器,自動裝配就會生效,而後就配置成功了

1.springboot在啓動的時候,會從類路徑下META-INF/spring.factories文件中獲取指定的值

2.將這些自動配置的類導入容器,自動配置類就會生效,幫咱們進行自動配置

3.springboot幫咱們作了咱們之前須要的配置.

4.整個J2EE的總體解決方案和自動配置都在springboot-autoconfigure的jar包中;

5.他會把全部須要導入的組件,以類名的方式返回,這些組件就會被添加到容器

6.容器中也會存在很是多的XxxAutoConfiguration的文件(@Bean),就是這些類給容器中導入了這個場景所須要的全部組件

7.有了自動配置類,就不須要寫配置文件

咱們找一個打開看看 : WebMvcAutoConfiguration

因此,真正實現是從classpath中搜尋全部的META-INF/spring.factories配置文件 ,並將其中對應的 org.springframework.boot.autoconfigure. 包下的配置項經過反射實例化爲對應標註了 @Configuration的JavaConfig形式的IOC容器配置類 , 而後將這些都彙總成爲一個實例並加載到IOC容器中。

2.Run

@SpringBootApplication
public class SpringbootDemo02Application {

    public static void main(String[] args) {        
        //該方法返回一個ConfigurableApplicationContext對象        
        //參數一:應用入口的類     參數類:命令行參數
        SpringApplication.run(SpringbootDemo02Application.class, args);
    }

}

SpringApplication.run分析

分析該方法主要分兩部分,一部分是SpringApplication的實例化,二是run方法的執行;

SpringApplication的實例化

1.推斷應用的類型是普通的項目仍是Web項目

2.查找並加載全部可用初始化器 , 設置到initializers屬性中

3.找出全部的應用程序監聽器,設置到listeners屬性中

4.推斷並設置main方法的定義類,找到運行的主類

3.談談你對springboot的理解

  • 自動裝配
  • run方法
相關文章
相關標籤/搜索