1. 程式人生 > 實用技巧 >SpringBoot 核心理論

SpringBoot 核心理論

1.SpringBoot

1.1 概念

SpringBoot是由Pivotal團隊在2013年開始研發、2014年4月釋出第一個版本的全新開源的輕量級框架。它基於Spring4.0設計,不僅繼承了Spring框架原有的優秀特性,而且還通過簡化配置來進一步簡化了Spring應用的整個搭建和開發過程。另外SpringBoot通過整合大量的框架使得依賴包的版本衝突,以及引用的不穩定性等問題得到了很好的解決。

  • 設計目的是用來簡化新 Spring 應用的初始搭建以及開發過程。
  • 核心:自動配置、基於 約定大於配置 原則。
  • 父依賴維護 SpringBoot 版本號即可
  • 核心註解:@EnableAutoConfiguration

1.2 核心依賴

SpringBoot 父依賴為核心依賴,其中預設管理了很多 jar 包的版本,所以我們再根 pom.xml 中如果不需要指定特殊的版本,可不指定 jar 包版本。

檢視核心依賴

  1. 進入 spring-boot-starter-parent
    <parent>
        <groupId>org.springframework.boot</groupId>
        <!-- 跟進 以下目錄,檢視父依賴的 -->
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
  1. 進入spring-boot-dependencies
<!-- 再進入   -->
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.3.1.RELEASE</version>
  </parent>

進入 spring-boot-dependencies-2.3.1.RELEASE.pom 檔案後,可發現在 properties

dependencyManagement

中有很多依賴已經配置並指定版本號好。

1.3 自動裝配(核心)

SpringBoot 的核心就在於 自動裝配

SpringBoot 自動裝配的過程:

SpringBoot 通過 @EnableAutoConfiguration 註解開啟自動裝配;載入 spring.factories 中註冊的各類 AutoConfiguration;當 AutoConfiguration 類滿足 @Conditional 註解中的條件時,則例項化該 AutoConfiguration 類中定義的 Bean,並注入 Spring 容器中。

@EnableAutoConfiguration

該註解由 @SpringBootApplication 引入,完成開啟自動裝配;掃描 autoconfigure jar 包 META-INF 下的 spring.factories 檔案,並載入其中註冊的 AutoConfigure 類等。

spring.factories

配置檔案,位於 autoconfigure jar 包 META-INF 目錄下;

AutoConfiguration

SpringBoot 中的自動配置類,例如 RedisAutoConfiguration 等;其中定義了三方元件整合 Spring 所需的初始化 Bean 和條件

@Conditional

SpringBoot 中以 @Conditional 開頭的條件註解;AutoConfiguration 需滿足其中的條件才可例項化

1.3 啟動器

各類三方元件starter

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

        <!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- Spring Boot Mail -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

        <!-- SpringBoot JDBC -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- 阿里資料庫連線池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.22</version>
        </dependency>

        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <!-- SpringBoot Redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

1.4 註解

SpringBoot 專案建立完會生成 ***Application 啟動類;

package pers.vincent.matrix;

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

@SpringBootApplication
public class MatrixApplication {

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

}

核心註解@SpringBootApplication

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.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.repository.Repository;

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

         // 排除指定自動配置類
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

          // 排除指定自動配置名
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

          // 指定掃描的基礎包,啟用註解元件的初始化
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};
       
         // 指定掃描的類,初始化
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

         // Bean名稱生成器
	@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

         // 指定是否代理 @Bean 方法
	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}

結構:

@SpringBootApplication

  • @SpringBootConfiguration
    • @Configuration
      • @Component
  • @EnableAutoConfiguration
    • @AutoConfigurationPackage
    • @Import(AutoConfigurationImportSelector.class)
  • @ComponentScan
    • @Repeatable(ComponentScans.class)
@SpringBootConfiguration: SpringBoot 配置
@Configuration:Spring 配置類
@Component:元件
    
@EnableAutoConfiguration:自動配置 (核心註解)
@AutoConfigurationPackage:自動配置包
@Import(AutoConfigurationPackages.Registrar.class):自動配置`包註冊`
@Import(AutoConfigurationImportSelector.class): 自動配置匯入選擇
@ConditionOnxxxx:如果條件都滿足,才能生效

@ComponentScan:掃描    

其餘註解:

  • @AliasFor:用於橋接到其他註解,其中的屬性指定所橋接的註解類

@EnableAutoConfiguration

@Import(AutoConfigurationImportSelector.class)

AutoConfigurationImportSelector 核心功能解析:

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    
    // 
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    
    // 載入 spring.factories 中的 EnableAutoConfiguration 的配置類
    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);
}