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相關配置,請自行忽略。