我把公司 10 年老系統改造 Maven,真香!!

Java技術棧發表於2020-09-23

公司有幾個老古董專案,應該是 10 年前開發的了,有一個是 JSP + Servlet,有一個還用的 SSH 框架,打包用的 Ant,是有多老啊,我想在座的各位很多都沒聽過吧。

為了持續整合、持續部署的需要,需要把這些老古董專案全改造成 Maven 管理,下面開搞。

快速建立一個 Maven 專案

Maven Archetype 介紹

如何快速建立一個 Maven 專案,可以通過 Maven 的 Archetype 來進行建立,Archetype 是 Maven 提供的各種各樣的工程模板,通過這些模板可以生成不同的 Maven 專案結構。

Maven 提供的 Archetype 列表如下:

http://maven.apache.org/archetypes/index.html

Archetype ArtifactIds Description
maven-archetype-archetype generate a sample archetype project.
maven-archetype-j2ee-simple generate a simplifed sample J2EE application.
maven-archetype-mojo generate a sample a sample Maven plugin.
maven-archetype-plugin generate a sample Maven plugin.
maven-archetype-plugin-site generate a sample Maven plugin site.
maven-archetype-portlet generate a sample JSR-268 Portlet.
maven-archetype-quickstart generate a sample Maven project.
maven-archetype-simple generate a simple Maven project.
maven-archetype-site generate a sample Maven site which demonstrates some of the supported document types like APT, XDoc, and FML and demonstrates how to i18n your site.
maven-archetype-site-simple generate a sample Maven site.
maven-archetype-webapp generate a sample Maven Webapp project.

這裡我們選擇 maven-archetype-quickstart 這個模板進行快速建立,因為它提供了一個標準的專案結構,基於這個基本專案結構可以進行後續擴充套件。

project
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- $package
    |           `-- App.java
    `-- test
        `-- java
            `-- $package
                `-- AppTest.java

生成 Maven 專案

1)通過 Maven 命令

Maven 提供了命令快速建立 Maven 專案:

mvn archetype:generate
-DarchetypeGroupId=org.apache.maven.archetypes
-DarchetypeArtifactId=maven-archetype-quickstart
-DarchetypeVersion=1.4

命令中指定我們前面所說的 Maven Archetype:maven-archetype-quickstart 資訊。

執行過程中會提示讓你輸入專案的 Naven 座標資訊,直到建立完成。基礎部分這裡不撰述了,需要完整 Maven 教程的關注公眾號Java技術棧在後臺回覆"mvn"獲取。

2)通過 IDEs

通過 IDE 也能快速建立 Maven 專案,現在 Java IDEs 都支援 Maven 或者自帶 Maven 外掛,下面以 Intellij IDEA 為例進行建立。

選擇 maven-archetype-quickstart:

輸入專案的 Naven 座標資訊:

選擇 Maven 及倉庫設定資訊:

等待專案構建完成,如下所示:

Maven 專案重構

Maven 專案配置

專案生成後,我們就可以把原系統的檔案移到新的 Maven 專案了,因生成的專案結構比較簡單,Maven 提供的 maven-archetype-webapp 模板也不符合要求:

我們的專案性質又是後臺系統,涉及到方方面面,所以還需要再完善其他資源目錄的建立:

- src
  - main
    - java
    - resources
    - filters
    - webapp
  - test
    - java
    - resources

這是一個比較標準的 Maven Web 專案結構,我把它弄成了一個基礎腳手架,還整合了各種現成的外掛和功能,後面其他專案轉 Maven 可以直接拿來套用。

已經上傳到了 Github:

https://github.com/javastacks/maven-demo-project

主要目錄結構介紹:

目錄 說明
src/main/java 原始碼目錄
src/main/resources 資源目錄
src/main/filters 多環境配置過濾目錄
src/main/webapp Web應用檔案目
src/test/java 測試程式碼目錄
src/test/resources 測試資源目錄

所有目錄建立完後,再根據檔案性質把原系統所有除了(*.jar)檔案移到對應的目錄,這裡沒什麼難度。

配置 Maven 環境資訊:

<build>
	<filters>
		<filter>src/main/filters/filter-${env}.properties</filter>
	</filters>

	<resources>
		<resource>
			<directory>src/main/resources/config</directory>
			<filtering>true</filtering>
		</resource>
		<resource>
			<directory>src/main/resources/resource</directory>
			<filtering>false</filtering>
		</resource>
	</resources>
	
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>${maven-compiler-plugin.version}</version>
		</plugin>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-war-plugin</artifactId>
			<version>${maven-war-plugin.version}</version>
			<configuration>
				<failOnMissingWebXml>false</failOnMissingWebXml>
			</configuration>
		</plugin>
	</plugins>

</build>

<profiles>
	<profile>
		<id>dev</id>
		<activation>
			<activeByDefault>true</activeByDefault>
		</activation>
		<properties>
			<env>dev</env>
		</properties>
	</profile>
	<profile>
		<id>test</id>
		<properties>
			<env>test</env>
		</properties>
	</profile>
	<profile>
		<id>mirror</id>
		<properties>
			<env>mirror</env>
		</properties>
	</profile>
	<profile>
		<id>prod</id>
		<properties>
			<env>prod</env>
		</properties>
	</profile>
</profiles>

Maven 依賴轉換

依賴轉換就是要把所有原系統的(*.jar)依賴包全部轉換為 Maven 依賴管理,這裡是難點,要解決編譯、啟動、執行時遇到的 jar 包衝突、版本衝突等異常。

我的思路是先把一些核心框架的依賴進行轉換,再進行一些比較獨立的公共工具包的轉換,最後就是一些不熟悉的依賴轉換。

引入 Maven 依賴的時候,看下其所有附屬的所有依賴,再逐漸從 lib 目錄刪除,直到全部刪除完成即轉換完成。

在找對應依賴的時候,如果中央倉庫找不到,其他遠端倉庫能找到的,就在公司私庫中新增該包所在的遠端倉庫代理配置。

如果中央倉庫或者其他遠端倉庫都找不到的,比如第三方的 SDK 包,就上傳到公司私庫。怎麼上傳到私庫,點選這裡閱讀,更多 Maven 教程在公眾號Java技術棧回覆maven進行閱讀。

根據 JAR 包找 Maven 依賴的時候,可能有多個名稱一樣的依賴,不知道引用哪個,這時候需要去原始 JAR 包中看下包名,根據包名就大概知道座標資訊了。

依賴傳遞:

在依賴轉換過程中,如果一個依賴又依賴了其他依賴,可以直接引用父依賴即可,如在老專案中存在:poi、poi-ooxm、poi-ooxml-schemas 這三個依賴:

但在 POI 依賴體系中,poi-ooxml 包又需要依賴其他兩個包,所以只需要引入 poi-ooxml 依賴即可:

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>

這樣就把這個包需要依賴的其他包都引進來了,這就是 Maven 管理依賴的好處,不會出現多包少包的情況,也能儘量避免依賴衝突。

依賴範圍:

在老專案中,所有 jar 包都在 web-inf/lib 目錄下,如:Servlet、JUnit,這些包在打完生產包之後也還在目錄下,沒有生命週期的管理。

在 Maven 中就能控制它們的生命週期:

<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<version>${javax.servlet-api.version}</version>
	<scope>provided</scope>
</dependency>

<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>${junit.version}</version>
	<scope>test</scope>
</dependency>

Servlet 只需要編譯時用到,JUnit 只需要測試時用到,控制好每個包的依賴範圍,做到每個包的作用範圍最小化。

解決衝突:

當傳遞的依賴版本不符合,或者是同一個包出現不同版本導致衝突的時候要學會使用排除:

或者強制指定包版本:

<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId>bcprov-jdk16</artifactId>
	<version>${bctsp-jdk16.version}</version>
</dependency>

有的時候,還要根據需要使用 classifier 指定不同 JDK 的版本:

<dependency>
	<groupId>com.test</groupId>
	<artifactId>test</artifactId>
	<version>${test.version}</version>
	<classifier>JDK6</classifier>
</dependency>

如原始碼編譯報錯,不知道引用的哪個 JAR 包、或者哪個版本,可以到原始專案中點對應的類引用進去看就知道了。

整個改造過程比較順利,就是編譯和執行時需要解決一些 JAR 包衝突導致的問題,根據上面的種種方法直至編譯、啟動正常。

以後可以舒舒服服用 Maven 咯。

整理了半天,無私分享給大家,希望你們能有收穫,覺得不錯,歡迎點贊、轉發喲~

近期熱文推薦:

1.Java 15 正式釋出, 14 個新特性,重新整理你的認知!!

2.終於靠開源專案弄到 IntelliJ IDEA 啟用碼了,真香!

3.我用 Java 8 寫了一段邏輯,同事直呼看不懂,你試試看。。

4.吊打 Tomcat ,Undertow 效能很炸!!

5.《Java開發手冊(嵩山版)》最新發布,速速下載!

覺得不錯,別忘了隨手點贊+轉發哦!

相關文章