開啟Spring Initializr個(gè)性化之旅

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

Josh Long

202006201751FnpKSR11

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

目標(biāo)

基本框架

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

個(gè)性化

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

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

Spring Initializr 是一個(gè)使用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)備

兩個(gè)組件

initializr 是必須的昔汉,ui界面是可選的懈万。

個(gè)性化

定制配置文件

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

@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

通過這種自定義的依賴配置昆咽,我們就可以控制配置項(xiàng)的合并和顯示順序驾凶。

Initializr擴(kuò)展

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

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

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

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

接著,我們定義兩個(gè) BuildCustomizer:一個(gè)用來增加maven依賴插件然痊,一個(gè)用來移除插件至朗。

@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 自身并不會(huì)使用這些自動(dòng)化配置剧浸,而是在生成項(xiàng)目時(shí)使用的蛙埂,但需要spring.factories注冊(cè)這些配置

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)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碑宴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子桑谍,更是在濱河造成了極大的恐慌延柠,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锣披,死亡現(xiàn)場離奇詭異贞间,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)雹仿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門增热,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人胧辽,你說我怎么就攤上這事峻仇。” “怎么了邑商?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵摄咆,是天一觀的道長凡蚜。 經(jīng)常有香客問我,道長吭从,這世上最難降的妖魔是什么朝蜘? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮涩金,結(jié)果婚禮上谱醇,老公的妹妹穿的比我還像新娘。我一直安慰自己步做,他們只是感情好枣抱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著辆床,像睡著了一般。 火紅的嫁衣襯著肌膚如雪桅狠。 梳的紋絲不亂的頭發(fā)上讼载,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音中跌,去河邊找鬼咨堤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛漩符,可吹牛的內(nèi)容都是我干的一喘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嗜暴,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼凸克!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起闷沥,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤萎战,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后舆逃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚂维,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年路狮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了虫啥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奄妨,死狀恐怖涂籽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情展蒂,我是刑警寧澤又活,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布苔咪,位于F島的核電站,受9級(jí)特大地震影響柳骄,放射性物質(zhì)發(fā)生泄漏团赏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一耐薯、第九天 我趴在偏房一處隱蔽的房頂上張望舔清。 院中可真熱鬧,春花似錦曲初、人聲如沸体谒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抒痒。三九已至,卻和暖如春颁褂,著一層夾襖步出監(jiān)牢的瞬間故响,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工颁独, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留彩届,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓誓酒,卻偏偏與公主長得像樟蠕,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子靠柑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354