天天看點

手寫自定義springboot-starter,感受架構的魅力和原理

一、前言

Springboot的自動配置原理,面試中經常問到,一直看也記不住,不如手寫一個starter,加深一下記憶。

看了之後發現大部分的starter都是這個原理,實踐才會記憶深刻。

核心思想:約定大于配置。

二、初探starter啟動原理

我們直接看看官網的starter是怎麼設計的,仿照這寫一個就行了!

我們Ctrl點選<artifactId>spring-boot-starter-web</artifactId>,進入内部pom,我們發現裡面有個

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
  <version>2.5.3</version>
  <scope>compile</scope>
</dependency>
           

在此Ctrl點選<artifactId>spring-boot-starter</artifactId>進入starter内部pom:

我們發現之後幹活的就是這個包依賴:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-autoconfigure</artifactId>
  <version>2.5.3</version>
  <scope>compile</scope>
</dependency>
           
手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

我們現在建立兩個項目即可:

  • spring-boot-starter(啟動器)
  • spring-boot-starter-autoconfigure(自動配置包)

小編看到官方這麼寫的提醒,大家可以按照官網的進行起名稱,不要學小編哈!!

您應該確定為您的啟動器提供适當的命名空間。不要以 . 開頭的子產品名稱spring-boot,即使您使用不同的 Maven groupId。我們将來可能會為您自動配置的内容提供官方支援。

根據經驗,您應該在啟動器之後命名組合子產品。例如,假設您正在為“acme”建立一個啟動器,并且您命名自動配置子產品acme-spring-boot和啟動器acme-spring-boot-starter。如果您隻有一個子產品将兩者結合起來,請将其命名為acme-spring-boot-starter.

三、項目搭建

1. 建立空白項目

手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

輸入總的項目名稱

手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

在空白項目裡建立兩個,這裡可以分開單獨建立,這裡小編跟着雷神一樣了,就不單獨建立項目了!!

手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

2. 建立maven項目

手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

包名和名稱:

手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

3. 建立springboot項目

手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

4. 項目架構

這裡把沒有用的都删除了!!可以不删

手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

四、配置

1. 在starter項目中引入自己的autoconfigure依賴

就是上面建立項目的設定的

<dependencies>
    <dependency>
        <groupId>com.wang</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>
           
手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

2. spring-boot-autoconfigure pom配置

<properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>${spring-boot.version}</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>
</dependencies>
           

還是把沒用的東西删除了,剩餘如下圖:

手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

五、編寫autoconfigure項目

1. 配置一個bean

首先删除了自動啟動類,咱們用不到,

在spring-boot-autoconfigure項目中建立一個bean,此時不需要讓這個bean在容器中,我們寫一個自己配置,讓他自動加入到容器中。

==這就是自動配置的思想==

/**
 * 這裡不需要讓在容器中,我們寫一個自己配置,讓他自動加入到容器中
 * @author wangzhenjun
 * @date 2022/10/14 16:26
 */
public class HelloService {

    @Autowired
    private MyProperties myProperties;

    public String HelloWord (String username){
        return myProperties.getPrefix() + username + myProperties.getSuffix();
    }
}
           

2. 編寫一個配置檔案

這裡為了擷取配置檔案中的屬性值,springboot自動配置源碼裡大部分都是,這樣實作在一個配置檔案中書寫,其他的可以按照開頭擷取到屬性和值!!

/**
 * @author wangzhenjun
 * @date 2022/10/14 16:28
 */
@Data
@ConfigurationProperties("wang.name")
public class MyProperties {

    private String prefix;
    private String suffix;
}
           

3. 編寫自動配置

import com.wang.springbootautoconfigure.properties.MyProperties;
import com.wang.springbootautoconfigure.service.HelloService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author wangzhenjun
 * @date 2022/10/14 16:33
 */
@Configuration
//沒有這個bean的時候才會生效
@ConditionalOnMissingBean(HelloService.class)
// 加載配置檔案,讓它成為容器中的bean
@EnableConfigurationProperties(MyProperties.class)
public class ServiceAutoConfiguration {


    /**
     * 把剛剛寫的服務,加入到容器中
     */
    @Bean
    public HelloService helloService (){

        return new HelloService();
    }
}
           

主要就是condition下的幾個注解,來完成bean是否加入到容器中:

常用的:

  • @ConditionalOnClass
  • @ConditionalOnMissingClass
  • @ConditionalOnBean
  • @ConditionalOnMissingBean
  • @ConditionalOnProperty
  • 在這裡插入圖檔描述

4. 建立spring.factories

我們看到源碼裡自動配置,就是從這個檔案擷取加載,是以我們模仿這建立一個,這樣就可以掃描加入容器中!!

手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

如果是springboot2.7以上就是:

檔案夾名稱:META-INF.spring

檔案名稱:org.springframework.boot.autoconfigure.AutoConfiguration.imports

手寫自定義springboot-starter,感受架構的魅力和原理

裡面直接寫全類名即可!

5. 打包

先把spring-boot-autoconfigure打包到本地庫,在打包spring-boot-starter,順序一定要有,不然找不到前者的包!!

手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

六、測試

我們那一個新項目進行測試,新項目小編就不帶大家建了!

1. 導入咱們的starter依賴

<dependency>
    <groupId>com.wang</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
           

2. 添加配置檔案

wang:
 name:
  prefix: hello
  suffix: 886
           
手寫自定義springboot-starter,感受架構的魅力和原理

在這裡插入圖檔描述

3. 建立controller測試類

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private HelloService helloService;

    @GetMapping("/starter")
    public String starter(){

        return helloService.HelloWord("tom");
    }
}
           

4. 測試通路

成功通路,不過中文是有亂碼的,小編找不到解決方法,有懂的還請留言告知!!

主流程通了就行,慢慢了解了自動配置的魅力!

總流程應該就是這樣的:

引入starter --- xxxAutoConfiguration --- 容器中放入元件 ---- 綁定xxxProperties ---- 配置項

手寫自定義springboot-starter,感受架構的魅力和原理

中文是亂碼,可能是servlet沒有吧,有懂的可以留言告訴小編方案,謝謝大家!!

手寫自定義springboot-starter,感受架構的魅力和原理

七、總結

一看會就,一動手就廢!大家還是要做自己實操,不要眼高手低,這樣才會有收獲,根本就是約定大于配置+SPI發現機制!

還有就是一些經常出現在源碼裡的注解,大家記住就可以自己寫starter了!

可以看下一小編的微信公衆号,和網站文章首發看,歡迎關注!!

繼續閱讀