Maven插件的開發

Maven是個很好用的打包編譯工具,也是目前自己正在使用的主力工具。對一些個性化的需求,編寫插件,實現一些特有的功能,還是非常有效的。這次剛好,有需求如是:maven編譯時用到數據庫表描述文件自動生成插件,需要從配置文件中讀取賬號密碼,而目前maven只提供了讀取properties文件到聲明週期的工具。而項目的通用配置文件是json,如果臨時加一個重複的properties文件,顯得多餘且沒必要。於是需求應運而生,開發一個讀取json文件到Maven生命週期的工具。

我叫它 json-loader-maven-plugin。

首先創建一個Maven空工程,我們從已有的Maven工程開始。

pom配置

基礎信息

基礎信息和普通項目沒什麼兩樣,需要注意的點如下

  • groupId: 組織ID,具有權威性,由於是github中的項目,所以命名爲com.github.用戶名
  • artifactId: Apache規定,凡是Maven插件命名必須以 maven-plugin結尾
  • packagin: 此處開發插件,因此打包類型爲 maven-plugin
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.github.zou8944</groupId>
  <artifactId>json-loader-maven-plugin</artifactId>
  <packaging>maven-plugin</packaging>
  <version>1.0.0</version>

依賴

我們會用到Maven Plugin API ,插件相關注解,比如@Mojo,還會用到單元測試(這裏使用JUnit)。再加上解決的一些依賴問題,得到必備的依賴項如下

  <dependencies>
    <!-- 基礎組件 -->
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>3.6.2</version>
    </dependency>
    <!-- 插件註解 -->
    <dependency>
      <groupId>org.apache.maven.plugin-tools</groupId>
      <artifactId>maven-plugin-annotations</artifactId>
      <version>3.6.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- maven project API,提供運行的整個project的各種API,比如讀取和動態設置依賴項等 -->
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-project</artifactId>
      <version>2.2.1</version>
    </dependency>
    <!-- 爲解決依賴問題而加,必須和maven-project保持同一版本-->
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-artifact</artifactId>
      <version>2.2.1</version>
    </dependency>
    <!-- 單元測試 -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13</version>
      <scope>test</scope>
    </dependency>
    <!-- 用於讀取json文件 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.61</version>
    </dependency>
  </dependencies>

編寫Mojo

Mojo是插件執行的目標類,在使用時和<goal>標籤對應,一個插件可以有多個Mojo。

對Mojo的編寫,一般集成AbstractMojo類,它實現了Mojo接口的必要方法,只留下一個execute()方法讓我們編寫業務邏輯。同時我們爲定義的類加上@Mojo註解,Maven在運行時就能夠檢測到它。

@Mojo(name = "read-project-json-to-properties", defaultPhase = LifecyclePhase.INITIALIZE)
public class ReadJsonMojo extends AbstractMojo {

  // 注入Maven環境
  @Parameter(defaultValue = "${project}", readonly = true, required = true)
  private MavenProject project;

  // 注入參數
  @Parameter
  private File[] files;

  @Override
  public void execute() throws MojoExecutionException, MojoFailureException {
    try {
      // 將文件解析爲properties對象
      Properties properties = parseFileProperties(files);
      // 將解析的properties對象加入到project實例中
      project.getProperties().putAll(properties);
    } catch (IOException e) {
      throw new MojoExecutionException("Error reading json from " + resource, e);
    }
  }
}

上述代碼是簡化後的,目的是爲了關注到插件的實現上,而不是業務邏輯。針對這段代碼,有如下幾點說明

  • @Mojo

    指定了Mojo名,對應goal,可設置默認工作的生命週期節點。

  • MavenProject屬性,代表了pom.xml下的<project>標籤下的所有內容,即Maven的運行環境。在Maven上下文創建時將會被注入。

  • File屬性,Maven支持直接將pom文件中指定的路徑直接解析成File並注入Mojo類。除了File,還支持如下類型,而他們,都是通過@Parameter註解實現的。

    • Boolean
    • Integer
    • Float-Point
    • Date
    • File
    • URL
    • Plain text
    • Enum
    • Array
    • Collection
    • Map
    • Properties
    • Object class

    具體的使用方法,可以參考官方文檔

單元測試

Unit test和普通Maven項目沒有太大區別,僅僅在於預設環境的不同,簡化代碼如下

public class ReadPropertiesMojoTest {

  private MavenProject projectStub;
  private ReadJsonMojo readJsonMojo;

  @Before
  public void setUp() {
     // 創建一個空的MavenProject對象
    projectStub = new MavenProject();
    // 創建剛纔的Mojo實例
    readJsonMojo = new ReadJsonMojo();
    // 顯示將MavenProject注入Mojo,set方法前面的代碼省略了,請注意。
    readJsonMojo.setProject(projectStub);
  }

  @Test
  public void readJsonFile() throws Exception {
    File testFile = constructTestFile();
    Properties baseProperties = constructComparedProperties();

    readJsonMojo.setFiles(new File[]{testFile});
    readJsonMojo.execute();

    Properties projectProperties = projectStub.getProperties();

    assertNotNull(projectProperties);
    assertNotEquals(0, projectProperties.size());
    assertEquals(baseProperties, projectProperties);
  }

  private File constructTestFile() throws IOException {
    . . . . . .
    return file;
  }

  private Properties constructComparedProperties() {
    . . . . . .
    return properties;
  }

}

安裝測試

單元測試後,可以安裝到本地倉庫進行測試

安裝

mvn clean install

命令行測試

可以直接通過命令行執行剛纔的插件

# 命令行執行格式
mvn groupId:artifactId:version:goal
# 本項目執行如下
mvn com.github.zou8944.json-loader-maven-plugin:1.0.0:read-project-json-to-properties

在其它項目中使用

在本機上的另一個項目中通過如下配置使用它

      <plugin>
        <groupId>com.github.zou8944</groupId>
        <artifactId>json-loader-maven-plugin</artifactId>
        <version>1.0.0</version>
        <executions>
          <execution>
            <!-- phase在@Mojo定義時默認爲intialize,因此這裏實際可以不寫 -->
            <phase>initialize</phase>
            <goals>
              <!-- goal,對應@Mojo設置的name -->
              <goal>read-project-json-to-properties</goal>
            </goals>
            <configuration>
              <files>
                 <!-- 指定文件路徑,Maven能夠自行解析成文件 -->
                <file>hello.json</file>
              </files>
            </configuration>
          </execution>
        </executions>
      </plugin>

遇到的坑

開發過程相對順利,其中一個依賴衝突導致卡了較長時間。

MavenProject類中引入import org.apache.maven.artifact.DependencyResolutionRequiredException類,但該類在默認的Maven-Artifact 3.6.2包中已經沒有了,找了幾個版本,發現只有2.2.1版本存在,因此參考baeldung的教程,自定義了依賴項,才使問題得以解決。即,將Maven-Artifact包修改爲2.2.1版本

    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-artifact</artifactId>
      <version>2.2.1</version>
    </dependency>

總結

通過該項目簡單地瞭解了Maven插件的開發方法,雖然簡單,卻提供了很多種可能性。

此外,本文中的代碼均爲簡化後的,源碼在github上,歡迎訪問,只不過需要注意:源碼的pom中包含了很多其它內容,比如遠程發佈相關配置、site相關配置,請自行忽略。

參考文檔

  1. Apache Plugin Developer Centre

  2. How to Create a Maven Plugin

  3. MojoHaus Properties Maven Plugin

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