小白都能聽懂的spring boot自動化配置原理

spring boot最核心的特性就是他的自動化配置特性,極大的減少了構建一個spring web工程的工作量。那麼你知道spring boot自動化配置的原理嗎?

先直接自定義一個user-spring-boot-starter組件,感受下自動化配置的魅力。

構建user-spring-boot-starter

pom依賴

   <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.laowan</groupId>
    <artifactId>user-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>user-spring-boot-starter</name>
    <description>user-spring-boot-starter</description>

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

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

添加配置屬性

spring.user.enabled=false
spring.user.name=laowan

創建UserPorperties屬性類使用配置屬性

@Data
@ConfigurationProperties("spring.user")
public class UserPorperties {
    private String name;
}

利用屬性類UserPorperties構建UserClient對象

public class UserClient {
    private UserPorperties userPorperties;
    public UserClient(){
    }

    public UserClient(UserPorperties userPorperties){
          this.userPorperties = userPorperties;
    }
    public String getName(){
        return userPorperties.getName();
    }
}

核心:創建UserAutoConfigure自動化配置類

@Configuration
@EnableConfigurationProperties(UserPorperties.class)
public class UserAutoConfigure {

    @Bean
    @ConditionalOnProperty(prefix = "spring.user",value ="enabled",havingValue = "true")
    public UserClient userClient(UserPorperties userPorperties){
        return new UserClient(userPorperties);
    }
}

說明:
@ConfigurationProperties(“spring.user”)
讀取以spring.user爲前綴的屬性文件,配置實體類

@EnableConfigurationProperties(UserPorperties.class)
將使用了@ConfigurationProperties 註解的類注入到spring容器中。
如果一個配置類只配置@ConfigurationProperties註解,而沒有使用@Component,那麼在IOC容器中是獲取不到properties 配置文件轉化的bean。
簡單來說@EnableConfigurationProperties 相當於把使用 @ConfigurationProperties 的類進行了一次注入。

@ConditionalOnProperty 屬性條件判斷,判斷指定的屬性是否有指定的值,滿足條件纔會初始化bean。

類似UserAutoConfigure這樣的自動化配置類是所有自動化配置組件的核心入口
我們需要的就是在引入了user-spring-boot-starter的依賴後,在spring容器啓動的時候,加載到這個自動化配置類,那麼就可以初始化UserClient,完成自動化配置。

加載自動化配置類的三種方式

由於Spring boot默認掃描的是跟啓動類平級的包。如果我們的Start跟啓動類不在同一個主包下,那麼就需要通過其他手段使得容器啓動加載到UserAutoConfigure自動化配置類。
方式一:創建spring.factories屬性配置文件
在user-spring-boot-starter工程下的/resources/META-INF目錄下創建spring.factories屬性配置文件,並在裏面指定自動化屬性配置類的全路徑。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.laowan.user.autoconfig.UserAutoConfigure

這是由於在spring boot開啓了自動化配置註解後,在容器啓動時,會自動加載所有
/resources/META-INF下的spring.factories文件,讀取org.springframework.boot.autoconfigure.EnableAutoConfiguration配置屬性,組成一個集合,然後去遍歷加載所有的自動化配置類。

建立demo工程測試:
1、引入user-spring-boot-starter的依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>com.laowan</groupId>
    <artifactId>user-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

2、配置屬性文件

spring.user.enabled=true
spring.user.name=laowan

3、編寫單元測試類

@SpringBootTest
@Slf4j
class DemoApplicationTests {

    @Autowired
    UserClient userClient;

    @Test
    void userClientTest() {
        log.info(userClient.getName());
    }
}

4、執行結果
在這裏插入圖片描述
說明我們的自動化配置生效

方式二:通過定義@EnableXXX註解來加載自動化配置文件
在user-spring-boot-starter工程下,新建@EnableUserClient註解,其中最核心的是通過
@Import註解注入了UserAutoConfigure.class。這樣在引用工程的啓動類上只要添加了@EnableUserClient註解,那麼就會加載到UserAutoConfigure自動化配置類


```javascript
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({UserAutoConfigure.class})
public @interface EnableUserClient {
}

測試:

@SpringBootApplication
@EnableUserClient
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

先註釋掉spring.factories中的配置項,然後執行單元測試,正確打印出配置屬性spring.user.name的值,說明我們的自動化配置生效。

方式三:通過@SpringBootApplication註解指定掃描的基礎包路徑

在測試工程demo中,配置@SpringBootApplication的屬性scanBasePackages

@SpringBootApplication(scanBasePackages = {"com.laowan.demo","com.laowan.user.autoconfig"})
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

通過@SpringBootApplication註解的scanBasePackages 屬性,指定掃描的包路徑。
這裏注意,一定要首先指定自己工程的根路徑,然後再執行自動化配置類的包路徑。
不然就只會掃描自動化配置類的包路徑,自己工程就不會掃描導致啓動出錯。

測試:
執行單元測試,發現配置屬性spring.user.name的值仍然可以正常打印,說明我們的自動化配置成功。

三種方式的比較:
三種加載自動化配置的方式,其核心都是解決Spring boot工程啓動只會默認掃描跟啓動類平級的包,導致其他不同包下的自動化配置類XXXAutoConfigure.class加載不到的問題。
方式一是通過spring.factories文件中配置org.springframework.boot.autoconfigure.EnableAutoConfiguration屬性指定自動化配置類XXXAutoConfigure.class的全路徑,是最主流的方式。
方式二通過自定義@EnableXXX註解並結合@Import註解加載自動化配置文件,在很多組件中也很常見,比如:
@EnableResourceServer

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ResourceServerConfiguration.class})
public @interface EnableResourceServer {
}

@EnableDiscoveryClient

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableDiscoveryClientImportSelector.class})
public @interface EnableDiscoveryClient {
    boolean autoRegister() default true;
}

方式三主要是對自動化配置原理的一種驗證,實際項目中不推薦。

自動化配置原理核心:
就是想辦法在spring容器啓動的時候,掃描到自動化配置類,然後根據屬性類和條件註解去聲明Bean,完成自動化配置。

實現配置項提示功能

在user-spring-boot-starter工程的/resources/META-INF目錄下創建spring-configuration-metadata.json

{
  "properties": [
    { "name": "spring.user.name",
      "defaultValue": "laowan",
      "description": "用戶名稱.",
      "type": "java.lang.String"
    },
    { "name": "spring.user.enabled",
      "defaultValue": false,
      "description": "是否啓用user組件.",
      "type": "java.lang.Boolean"
    }
  ]
}

這樣在引用工程中配置相關屬性,就會出現提示了。
在這裏插入圖片描述

通用規定

1、spring官方自己定義的starter組件,命名規則:spring-boot-starter-組件名
如:
spring-boot-starter-web
spring-boot-starter-jdbc
spring-boot-starter-security

非官方定義的start組件,命名規則:組件名-spring-boot-starter
如:
mybatis-spring-boot-starter

2、自動化配置類命名:XXXAutoConfiguration

3、starter組件的常規目錄結構分析
一般分爲2個工程,一個xxx-spring-boot-starter工程,通過spring.provides指定依賴服務模塊;
一個xxx-spring-boot-starter-autoconfigure模塊,通過定義spring.factories指定自動化配置文件加載路徑,定義spring-configuration-metadata.json實現自動化配置。
在這裏插入圖片描述

核心註解

在構建starter的過程中,涉及到一些註解
@EnableAutoConfiguration 開啓自動化配置功能,包含在@SpringBootApplication註解中,可以通過exclude屬性,過濾掉一些不需要開啓自動化配置的組件。

@Import 通過快速導入的方式實現把實例加入spring的IOC容器中,@Import只能用在類上

@ConfigurationProperties(“spring.user”) 加載前綴爲spring.user的屬性去配置當前類,但是並不會加載到spring容器中,需要配合@Component或者@EnableConfigurationProperties去使用。
@EnableConfigurationProperties(UserPorperties.class) 使 使用了@ConfigurationProperties註解配置的類生效,也就是注入到spring容器中

條件註解@Conditional
可以放在加了@Configuration的配置類上面,也可以放在使用@Bean定義bean的時候。用來判斷是否開啓配置或是否注入bean。
@ConditionalOnBean:當容器中有指定的Bean的條件下
@ConditionalOnClass:當類路徑下有指定的類的條件下
@ConditionalOnExpression:基於SpEL表達式作爲判斷條件
@ConditionalOnJava:基於JVM版本作爲判斷條件
@ConditionalOnJndi:在JNDI存在的條件下查找指定的位置
@ConditionalOnMissingBean:當容器中沒有指定Bean的情況下
@ConditionalOnMissingClass:當類路徑下沒有指定的類的條件下
@ConditionalOnNotWebApplication:當前項目不是Web項目的條件下
@ConditionalOnProperty:指定的屬性是否有指定的值
@ConditionalOnResource:類路徑下是否有指定的資源
@ConditionalOnSingleCandidate:當指定的Bean在容器中只有一個,或者在有多個Bean的情況下,用來指定首選的Bean
@ConditionalOnWebApplication:當前項目是Web項目的條件下

總結

1、自動化配置的原理:
(1)、加載自動化配置類
通過@EnableAutoConfiguration開啓自動化配置機制,原理是通過類加載器去掃描目錄下所有spring.factories文件,讀取org.springframework.boot.autoconfigure.EnableAutoConfiguration屬性,然後去加載XXXAutoConfigure自動化配置類。這個是通用的加載方式,適合批量默認自動開啓的組件。

針對某些特定組件,沒有定義spring.factories文件,則需要通過在啓動類上添加@EnableXXX的註解,通過@Import導入指定的自動化配置類,這種方式適合單一控制,默認不開啓自動化配置的組件。

(2)、根據讀取到的自動化配置類,完成相關配置過程
XXXAutoConfigure自動化配置類中根據spring boot相關注解,讀取相關屬性文件,並根據@Conditional條件註解判斷是否開啓自動化配置,是否實例化Bean。

2、自動化配置類加載的三種方式

3、怎麼自定義一個starter組件以及相關的規範

4、自動化配置過程中,常見註解的說明

spring boot自動化配置的原理,你明白了嗎?

覺得有用,記得點贊加關注。

實戰代碼Git地址:https://github.com/StarlightWANLI/auto-config.git

在這裏插入圖片描述

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