﻿# 認識 Apache Maven 優異的 Java 專案範本引擎 - Maven Archetype Plugin

現在很多 Java 的 IDE 工具都有內建 [Maven Archetype Plugin](https://maven.apache.org/archetype/maven-archetype-plugin/index.html) 作為建立新專案時的專案範本，你只要安裝 Apache Maven 之後，也可以很輕易的透過 CLI 介面來使用。今天這篇文章我想來介紹這套工具，並且分享一個可以大幅提昇執行速度的小技巧。

### Maven Archetype Plugin 簡介

Archetype Plugin 允許使用者從一個既有的**專案範本**，快速建立一個以 Maven 為基礎的全新專案。而在 Maven 的世界裡，這個**專案範本**又稱 `archetype` (原型)。

關於 `archetype` 這個英文單字由於對台灣人來說比較陌生，比較難用中文好好理解，但從英英字典的翻譯中可以看到他的定義是 "**a very typical example of a particular type of person or thing**"，簡單翻譯一下這句的意思就是：「一種特定人事物類型的經典範例」。因此，你可以把 `archetype` 思考為：「我有一種特定用途的應用程式類型，我為這種應用程式設計了一個**原型**，好讓日後要開發這類應用程式的人，可以依據這個原型為基礎，打造一個全新的應用程式」。

### Maven Archetype Plugin 主要架構

Archetype Plugin 主要的任務就只有兩個：

1.  從既有 `archetype` 建立新專案
2.  從既有專案建立 `archetype`

他的整體架構如下：

![Maven Archetype Plugin Overview](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/24c27b0cd4747eb2f54e-189476627-3758b6cf-b9d9-40dd-b0b5-54e637661caf.png)

### 從既有 `archetype` 建立新專案

要使用 Archetype Plugin 其實非常簡單，主要有三個步驟：

1.  準備一個 `archetype` 的來源
    
    預設 `archetype` 有三種不同的來源，這個來源又稱 `archetypeCatalog` (原型類別)，分別是 `remote`, `local`, `internal` 三種。
    
    當你在執行 `mvn archetype:generate` 命令的時候，這個 `archetypeCatalog` (原型類別) 的預設值為 `remote,local`，因此每次建立專案時，都會先從 `remote` (遠端) 下載一份 `archetype` 原型類別回來 ([archetype-catalog.xml](https://repo.maven.apache.org/maven2/archetype-catalog.xml))，再去抓 `local` (本地) 的原型類別。
    
    所謂 `remote` 原型類別，就是官方從 [ArchetypeCatalog](https://maven.apache.org/archetype/archetype-models/archetype-catalog/archetype-catalog.html) 維護的一份清單。裡面包含了許多社群提交的專案範本。
    
    所謂 `local` 原型類別，就是你在本機曾經使用過的專案範本，或是你直接從本地專案產生的專案範本。
    
    所謂 `internal` 原型類別，就是 [Maven Archetype Plugin](https://maven.apache.org/archetype/maven-archetype-plugin/index.html) 內建的專案範本。
    
2.  選擇一份 `archetype` 當成專案範本
    
    由於預設這份來自遠端的 [archetype-catalog.xml](https://repo.maven.apache.org/maven2/archetype-catalog.xml) 原型類別還蠻大的，內容是一份 XML 檔案，整體大小有 `12.3MB` 之多，當 `repo.maven.apache.org` 網站的連線速度變慢的時候，下載時間可能會高達 2 分鐘之久，快的時候大概 2 ~ 3 秒左右。
    
    你可以試試輸入以下命令，他會列出三千多份 `archetype` 讓你選擇，是不是很多！😅
    
    ```bash
    mvn archetype:generate -DarchetypeCatalog=remote
    ```
    
    > 我把這 3,000 多份 `archetype` 放在我的 [Gist](https://gist.github.com/doggy8088/675cebedcd74db14d49984728b4ad010) 讓大家可以方便快速瀏覽！
    
    由於 `archetype` 非常多，你也可以用以下命令提供篩選條件 (`-Dfilter=[groupId:]artifactId`)：
    
    ```bash
    mvn archetype:generate -Dfilter=am.ik.archetype:spring
    ```
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/1292c755b5293c0aa1c8-189477688-6d018d2d-eb4a-427b-8f8a-64d934f9bb49.png)
    
3.  提供這份 `archetype` 專案範本所需的參數設定
    
    由於每份 `archetype` 專案範本都可以自訂參數傳入，因此每個 `archetype` 可能會用到的參數都不太一樣。不過，你在執行 `mvn archetype:generate` 時，預設就會選用**互動模式**(`-Dinteractive=true`)，因此你在建立專案的時候，他會在 CLI 介面提醒你該設定些什麼，所以沒甚麼好擔心的。
    
    如果要用**非互動模式**(`-Dinteractive=false`)或稱**批次模式**(`-B`)來執行的話，可能就要設法取得所有參數才能執行。例如我以建立 Spring Boot 專案為例，你可能需要這樣執行：
    
    Bash
    
    ```bash
    mvn archetype:generate -B \
      -DarchetypeGroupId=am.ik.archetype \
      -DarchetypeArtifactId=spring-boot-blank-archetype \
      -DarchetypeVersion=1.0.6 \
      -DgroupId=com.duotify \
      -DartifactId=demo1 \
      -Dversion=1.0-SNAPSHOT
    ```
    
    PowerShell
    
    ```powershell
    mvn archetype:generate -B `
      '-DarchetypeGroupId=am.ik.archetype' `
      '-DarchetypeArtifactId=spring-boot-blank-archetype' `
      '-DarchetypeVersion=1.0.6' `
      '-DgroupId=com.duotify' `
      '-DartifactId=demo2' `
      '-Dversion=1.0-SNAPSHOT'
    ```
    
    Command Prompt
    
    ```batch
    mvn archetype:generate -B ^
      -DarchetypeGroupId=am.ik.archetype ^
      -DarchetypeArtifactId=spring-boot-blank-archetype ^
      -DarchetypeVersion=1.0.6 ^
      -DgroupId=com.duotify ^
      -DartifactId=demo3 ^
      -Dversion=1.0-SNAPSHOT
    ```
    
    > 三種不同的 Shell 環境有不同的命令寫法，文章真的很難寫！😅
    

### 提升建立新專案的速度

我有發現用 `mvn archetype:generate` 建立專案時，執行速度異常的慢，就是因為 `archetypeCatalog` (原型類別) 的預設值為 `remote,local`，所以無論如何他都一定會先下載 [archetype-catalog.xml](https://repo.maven.apache.org/maven2/archetype-catalog.xml) 回來，浪費了頻寬，也浪費了寶貴的時間。

我們曾經用過的 `archetype`，其實都會透過 `mvn` 下載到 `local` 的 Maven Repository 裡面，如果你認為不會有新版的話，其實可以把指令稍微調整一下，跳過 `archetypeCatalog` 的 `remote` 來源即可。以下我用 PowerShell 為例：

-   選用 `-DarchetypeCatalog=local` 本地原型類別
    
    ```powershell
    mvn archetype:generate -B `
      '-DarchetypeCatalog=local' `
      '-DarchetypeGroupId=am.ik.archetype' `
      '-DarchetypeArtifactId=spring-boot-blank-archetype' `
      '-DarchetypeVersion=1.0.6' `
      '-DgroupId=com.duotify' `
      '-DartifactId=demo2' `
      '-Dversion=1.0-SNAPSHOT'
    ```
    
-   選用 `-DarchetypeCatalog=internal` 內建原型類別
    
    ```powershell
    mvn archetype:generate -B `
      '-DarchetypeCatalog=internal' `
      '-DarchetypeGroupId=am.ik.archetype' `
      '-DarchetypeArtifactId=spring-boot-blank-archetype' `
      '-DarchetypeVersion=1.0.6' `
      '-DgroupId=com.duotify' `
      '-DartifactId=demo2' `
      '-Dversion=1.0-SNAPSHOT'
    ```
    

其實你在 `internal` 與 `local` 原型類別，都找不到 `am.ik.archetype:spring-boot-blank-archetype` 這份 `archetype` 才對，但這個命令可以讓你跳過下載 `remote` 目錄，找不到之後，就會直接從 `local` 的 Maven Repository 找到 `am.ik.archetype:spring-boot-blank-archetype` 這份 `Artifact`，所以一樣可以安裝成功，而且可以讓執行時間從 2 分鐘驟降到 1 ~ 2 秒左右！👍

> 參考: [Generate project using an alternative catalog](https://maven.apache.org/archetype/maven-archetype-plugin/examples/generate-alternative-catalog.html)

### 從既有專案建立 `archetype`

完整的建立過程可以參考 [Archetype creation](https://maven.apache.org/archetype/maven-archetype-plugin/advanced-usage.html) 文件說明，實作的步驟如下：

1.  建立 `~/.m2/settings.xml` 檔案
    
    由於 Maven 預設並不會幫你產生 `~/.m2/settings.xml` 檔案，你必須手動建立這份 XML 檔才能進行下一步：
    
    ```xml
    <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
      <localRepository/>
      <interactiveMode/>
      <offline/>
      <pluginGroups/>
      <servers/>
      <mirrors/>
      <proxies/>
      <profiles/>
      <activeProfiles/>
    </settings>
    ```
    
    > 詳見 [Settings Reference](https://maven.apache.org/settings.html) 與 [Why maven settings.xml file is not there? - Stack Overflow](https://stackoverflow.com/a/60827960/910074)
    
2.  找到一個現有的 Maven 專案，執行以下命令
    
    ```bash
    mvn archetype:create-from-project
    ```
    
    > 這個命令會將現有專案在 `target/generated-sources/archetype` 資料夾建立一個 `archetype` 專案，而且它會全自動幫你把**現有專案的原始碼**進行調整，調整成「專案範本」的樣子，在 `target/generated-sources/archetype/pom.xml` 檔案中會有這個 `archetype` 專案的完整資訊。
    
3.  微調剛建立的 `archetype` 專案
    
    如我在 [如何將私有的 JAR 檔加入到由 Apache Maven 管理的 Java 專案中](/post/2022/09/08/How-to-add-3rd-party-JARs-to-Maven-managed-Java-project) 文章中提到的觀念，這個 `pom.xml` 檔案中有四個最重要的參數，記得要先調整一下，尤其是 `version` 的設定：
    
    ```xml
    <groupId>com.duotify</groupId>
    <artifactId>myapp-archetype</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>maven-archetype</packaging>
    ```
    
    如果你希望在未來建立新專案後可以執行一些程式碼，做一些專案的結構調整或是做一些檔案的初始化動作，你可以在 `target/generated-sources/archetype/src/main/resources/META-INF/` 目錄下建立一個 `archetype-post-generate.groovy` 程式，只要用 [Apache Groovy](https://groovy-lang.org/) 語言撰寫這份腳本即可。
    
4.  將新的 `archetype` 專案安裝到 `local` Maven Repository 裡面
    
    ```bash
    cd target/generated-sources/archetype/
    mvn install
    ```
    
5.  測試從 `local` 原型類別來源建立一個新專案
    
    先建立一個空資料夾，並從 `local` 原型類別來源建立一個新專案
    
    ```bash
    mvn archetype:generate -DarchetypeCatalog=local
    ```
    
    你也可以用 `-B` 批次模式快速建立新專案：
    
    ```powershell
    mvn archetype:generate -B `
      '-DarchetypeCatalog=local' `
      '-DarchetypeGroupId=com.duotify' `
      '-DarchetypeArtifactId=myapp-archetype' `
      '-DarchetypeVersion=0.0.1-SNAPSHOT' `
      '-DgroupId=com.duotify' `
      '-DartifactId=demo2' `
      '-Dversion=1.0'
    ```
    

### 更多 Maven Archetype Plugin 用法

-   查詢 Archetype Plugin 不同 `goal` 的用法說明：
    
    ```bash
    mvn archetype:help -Ddetail=true
    ```
    
    > 詳見 [Maven Archetype Plugin - Plugin Documentation](https://maven.apache.org/archetype/maven-archetype-plugin/plugin-info.html)
    
-   更新位於 `local` 的 `archetype` 的來源
    
    這個命令在官網並沒有寫的很清楚，但他的意思就是將你當前目錄下的 `archetype` 專案重新建置，並且更新 `~/.m2/repository/archetype-catalog.xml` 檔案。
    
    ```bash
    mvn archetype:update-local-catalog
    ```
    
    > 你必須在 `target/generated-sources/archetype/` 目錄下執行這個命令。
    

### 相關連結

-   [Maven Archetype](https://maven.apache.org/archetype/index.html)
    -   [Archetype Repository](https://maven.apache.org/archetype/maven-archetype-plugin/archetype-repository.html)
-   [Maven Archetype Plugin](https://maven.apache.org/archetype/maven-archetype-plugin/index.html)
    -   [Project creation](https://maven.apache.org/archetype/maven-archetype-plugin/usage.html)
    -   [Archetype creation](https://maven.apache.org/archetype/maven-archetype-plugin/advanced-usage.html)
    -   [Generate project in batch mode](https://maven.apache.org/archetype/maven-archetype-plugin/examples/generate-batch.html)
    -   [Generate project using an alternative catalog](https://maven.apache.org/archetype/maven-archetype-plugin/examples/generate-alternative-catalog.html)
    -   [Create an archetype from a multi-module project](https://maven.apache.org/archetype/maven-archetype-plugin/examples/create-multi-module-project.html)
    -   [How does the Archetype Plugin know about archetypes?](https://maven.apache.org/archetype/maven-archetype-plugin/specification/archetype-catalog.html)
