springboot自動裝配原理解析(源碼級別詳細解析)

首先我們先看下核心文件
1.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.qiu</groupId>
    <artifactId>springboot-01-helloworld</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-01-helloworld</name>
    <description>qiu first springboot project</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

先挑出第一個來細講:

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

點進去看源碼:

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

結果又來了一個parent,這個時候我們再點進去看
在這裏插入圖片描述
終於沒有了
再往下滑動會發現:
這裏管理存放着大量的jar包.
所以說pom.xml裏

  • spring-boot-dependencies:核心依賴在父工程中
    所以說這就是爲什麼不用寫版本號的原因,因爲上面的父工程已經管理了,有這些管理倉庫了.
    2.啓動器
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>` 

啓動器:說白了就是springboot的啓動場景

  • 比如說spring-boot-starter-web,他就會幫我們自動導入web環境下所有的依賴
  • springboot會將所有的功能場景會變成一個個啓動器
  • 我們要使用什麼功能就只需要找到對應的啓動器就好了 starter
  • 在這裏插入圖片描述在這裏插入圖片描述然後就是主程序了:
    3.主程序
package com.qiu;

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:標註這個類是一個springboot的應用

SpringApplication.run:將springboot的應用啓動

  • 註解:我們查看源碼
    在這裏插入圖片描述

@SpringBootConfiguration:springboot的配置
在這裏插入圖片描述@Configuration:spring配置類:說明啓動類也是一個配置類
然後在點進去:
在這裏插入圖片描述@Component:說明這也是一個spring的組件

@EnableAutoConfiguration:自動配置
點擊源碼進去:
在這裏插入圖片描述@AutoConfigurationPackage:自動配置包:自動配置包註冊
在這裏插入圖片描述在這裏插入圖片描述
@Import(AutoConfigurationImportSelector.class):自動導入選擇
再點進去:

這個類中的一段代碼如下:獲取所有的配置

List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes 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;
	}

在這裏插入圖片描述爲的就是將啓動類中所有資源被導入
META-INF/spring.factories:自動配置的核心文件
在這裏插入圖片描述在這裏插入圖片描述 Properties properties = PropertiesLoaderUtils.loadProperties(resource);
所有的資源加載到配置類中
在這裏插入圖片描述
結論:springboot的所有自動配置都是在啓動的時候掃描並加載 spring.factories但是不一定生效,要判斷條件是否成立,只要導入了對應的start,就有了對應的啓動器,有了啓動器,我們的自動裝配,就會生效,然後就配置成功了
步驟:

  1. springboot在啓動的時候,從類路徑下/META-INF/spring.factories獲取指定的值
  2. 將這些自動配置的類導入容器,自動配置類就會生效,幫我們自動配置
  3. 以前我們需要自動配置的東西,現在springboot幫我們做了
  4. 整個javaEE,解決方案和自動配置的東西都在 spring-boot-autoconfigure-2.2.7.RELEASE.jar裏面
  5. 它會把所有需要導入的組件,以類名的方式返回,這些組件就會被添加到容器
    在這裏插入圖片描述

6.容器中也會存在非常多的XXXAutoConfiguration的文件,就是這些類給容器中導入這些場景需要的所有的組件,並自動配置@Configuration,javaConfig
7. 有了自動配置類,免去了我們手動編寫配置文件的工作

問題:
我們都知道:spring.factories這個文件中有所有的配置類,爲什麼這麼多配置類中有的文件沒有生效,而需要導入對應的start才能起作用?
核心註解@ConditionOn XXX :如果這裏面的條件都滿足纔會生效!
比如說會判斷jar包存不存在,如果不存在則所相對應的類就不會生效,所以說就算遍歷了全部的配置類,但也不是說一定都有用.

上面一大串都是在將關於註解裏面的,但是在主程序中不止是註解,他還有一個SpringApplication類,還有一個run方法
首先:springAppllication:
這個類主要做了以下四件事情:

1、推斷應用的類型是普通的項目還是Web項目

2、查找並加載所有可用初始化器 , 設置到initializers屬性中

3、找出所有的應用程序監聽器,設置到listeners屬性中

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

查看構造器:

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
    // ......
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.setInitializers(this.getSpringFactoriesInstances();
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章