開啟Spring Initializr個性化之旅

Every good Spring Boot project usually starts at https://start.spring.io/

Josh Long

202006201751FnpKSR11

背景介紹,自己的項目或者公司的項目一般需要維護(hù)很多定制化的模塊時,都是上傳到maven私服中方便使用,但存在一個問題,每次需要相關(guān)的package需要去翻文檔或者看bom,不能在建項目的時間直接引入,參考了start.spring.io,嘗試搭建自己的spring initializr服務(wù),同時整合自己的一些package,提供個性化服務(wù),快速開發(fā)。

目標(biāo)

基本框架

18077Y13ii51
  • Spring Initializr 提供核心REST API,可以整合到UI或者IDE(如Intellij IDEA),直接生成項目
  • https://start.spring.io 提供web界面,強(qiáng)依賴于 Spring Initializr,顯示數(shù)據(jù)來源于 Spring Properties,定制化主要是使用 Spring Initializr 提供的SPI
  • 除此之外,Spring.io 提供 Spring Boot metadata endpoint,Spring Initializr 會使用metadata作為外部數(shù)據(jù)源,以確保生成的Spring Boot版本是最新的

個性化

https://start.spring.io/ 雖然已經(jīng)提供了非常優(yōu)秀的Spring Boot Start,但在某些場景下,仍然需要做一些定制化,比如:

  1. 由于網(wǎng)絡(luò)限制,需要搭建一個自己的實例
  2. 定制化自己的UI界面
  3. 提供一些自己的配置或依賴,如公司內(nèi)部的starter

Spring Initializr 是一個使用Spring Boot搭建的模塊化應(yīng)用,所以還是很容易擴(kuò)展的

版本

由于官方Spring Initializr以及提供了bom,所以我們直接基于最新的bom版本搭建即可。

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>io.spring.initializr</groupId>
        <artifactId>initializr-bom</artifactId>
        <version>0.8.0.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

搭建流程

準(zhǔn)備

兩個組件

initializr 是必須的,ui界面是可選的。

個性化

定制配置文件

可以基于 InitializrProperties 定義 application.yml,產(chǎn)出核心依賴。Spring Initializr 也允許我們使用 InitializrMetadataProvider 定義metadata,因此,我們可以創(chuàng)建一個 CustomInitializrProperties 類 來讀取不同配置文件的配置項。

@Configuration
@EnableConfigurationProperties(CustomInitializrProperties.class)
public class CustomInitializrConfiguration {

  @Bean
  public DefaultInitializrMetadataProvider customInitializrMetadataProvider(InitializrProperties initializrProperties,
      CustomInitializrProperties customInitializrProperties,
      InitializrMetadataUpdateStrategy initializrMetadataUpdateStrategy) {
    InitializrMetadata meta = InitializrMetadataBuilder.fromInitializrProperties(customInitializrProperties.getInitializr())
        .withInitializrProperties(initializrProperties, true).build();
    return new DefaultInitializrMetadataProvider(meta, initializrMetadataUpdateStrategy);
  }
}


@Data
@ConfigurationProperties("custom")
public class CustomInitializrProperties {
  @NestedConfigurationProperty
  InitializrProperties initializr = new InitializrProperties();
}

配置是通過 StartApplication 來加載的,但由于應(yīng)用并沒有使用組件掃描,我們需要在配置文件里進(jìn)行自定義設(shè)置:

custom:
  initializr:
    dependencies:
      - name: Custom Dependencies
        content:
          - name: Custom dependency
            id: custom-dependency
            groupId: your.domain
            artifactId: custom-artifact
            starter: false
            description: My first custom dependency for the Spring Initializr

通過這種自定義的依賴配置,我們就可以控制配置項的合并和顯示順序。

Initializr擴(kuò)展

通過配置文件自定義依賴,并不是總能滿足我們的需求,有時候我們還需要自定義一些代碼片段,這個時候就需要使用 Spring Initializr 提供的一些擴(kuò)展鉤子:

  • BuildCustomizer:定義Maven/Gradle構(gòu)建過程,如增加maven build插件
  • ProjectContributor:定義一些個性化的項目目錄或者文件
  • MainSourceCodeCustomizer, MainCompilationUnitCustomizer, MainApplicationTypeCustomizer, TestSourceCodeCustomizer, TestApplicationTypeCustomizer:項目的源碼生成或修改,而不局限于項目語言
  • GitIgnoreCustomizer:定義gitignore文件
  • HelpDocumentCustomizer:定義 HELP.md文件
  • ProjectDescriptionCustomizer:通常用于適應(yīng)項目描述,例如自動解決框架版本和語言級別的無效組合。

舉例,如果我們需要在生成項目中增加maven插件,則需要使用一種所謂的“偽”依賴( pseudo dependency)。首先我們需要定義一個像這樣的依賴:

custom:
  initializr:
    dependencies:
      - name: Custom Dependencies
        content:
          - name: Custom Maven Plugin
            id: custom-maven-plugin
            groupId: your.domain
            artifactId: custom-maven-plugin
            version: 1.0.0
            starter: false
            description: Configures custom Maven plugin integration for project scans

接著,我們定義兩個 BuildCustomizer:一個用來增加maven依賴插件,一個用來移除插件。

@ProjectGenerationConfiguration
@ConditionalOnRequestedDependency("custom-maven-plugin")
public class CustomMavenPluginConfiguration {

  @Bean
  public BuildCustomizer<MavenBuild> customPluginConfigurer() {
    return (MavenBuild build) -> {
      build.dependencies().ids().filter(it -> it.equals("custom-maven-plugin"))
          .findFirst()
          .map(r -> build.dependencies().get(r)).map(r -> {
        build.plugins().add(r.getGroupId(), r.getArtifactId(),
            (plugin) -> plugin.execution("my-execution",
                (first) -> first.goal("scan").configuration((conf) -> {conf.add("failOnSeverity", "MAJOR");})
            ));
        return build;
      }).orElse(build);
    };
  }


  @Bean
  public BuildCustomizer<MavenBuild> customPluginDependencyRemoval() {
    return build -> build.dependencies().remove("custom-maven-plugin");
  }
}

注意使用注解,Spring Initializr 自身并不會使用這些自動化配置,而是在生成項目時使用的,但需要spring.factories注冊這些配置

io.spring.initializr.generator.project.ProjectGenerationConfiguration=\
  io.spring.start.site.extension.StartProjectGenerationConfiguration, \
  io.spring.start.site.CustomMavenPluginConfiguration

最終產(chǎn)生的pom類似這樣:

<plugin>
    <groupId>your.domain</groupId>
    <artifactId>custom-maven-plugin</artifactId>
    <version>1.0.0</version>
    <executions>
        <execution>
            <id>my-execution</id>
            <goals>
                <goal>scan</goal>
            </goals>
            <configuration>
                <failOnSeverity>MAJOR</failOnSeverity>
            </configuration>
        </execution>
    </executions>
</plugin>

結(jié)語

拋磚引玉,這篇文章只是簡單介紹了Spring Initializr的一些定制化方法,更多更好的擴(kuò)展方式還需要你去發(fā)現(xiàn)。

本文由 歧途老農(nóng) 創(chuàng)作,采用 CC BY 4.0 CN 協(xié)議 進(jìn)行許可。 可自由轉(zhuǎn)載、引用,但需署名作者且注明文章出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容