1. 程式人生 > >Maven 那點事兒(轉)

Maven 那點事兒(轉)

做到 conn active cep ant tab name www color

0. 前言

Jason Van Zyl,在 Java 十大風雲人物排行榜上或許會看到他。

這兄弟是幹嘛的?

他就是 Maven 的創始人,人們都尊稱他為“Maven 他爸”。

毋庸置疑,Jason 也是一個禿頂。James Gosling、Rod Johnson、Gavin King,你們可以告訴我為什麽嗎?

您曾經是否會遇到這些問題:

  • 我們要開發一個 Java 項目,為了保證編譯通過,我們會到處去尋找 jar 包。當編譯通過了,在運行的時候,卻發現ClassNotFoundException,臥槽!還差 jar 包啊?再去找找吧。

  • 每個 Java 項目的目錄結構都沒有一個統一的標準,配置文件到處都是,單元測試代碼到底應該放在哪裏,沒有一個權威的規範。

  • 可使用 Ant 做為項目構建工具,它可以自動化地完成編譯、測試、打包等任務,確實為我們省了不少事兒,但編寫 Ant 的 XML 腳本絕非是一件輕松的事情。

有了 Maven,以上這一切都不再是問題了。

Jason 就是 Java 開發規範的“救世主”!他給我們帶來了一種全新的項目構建方式,讓我們的開發工作更加高效。

不僅如此,Jason 還是一名“野心家”,他不僅希望每個 Java 開發者都能使用他定義的規範,還要我們都從他家裏去獲取 jar 包(他家就是 Maven 中央倉庫),我們只需告訴他,我們想要的 jar 包具體在什麽位置即可(這個位置就是 Maven 坐標)。

看來 Jason 要做的是兩件事情:

  1. 統一開發規範與工具

  2. 統一管理 jar 包

這兩件事情他都做到了,而且還做了更多的事情。

工欲善其事,必先利其器。咱們也來玩玩 Maven 這貨吧!先得去下載一個。

1. 安裝 Maven

Maven 是 Apache 基金會的頂級項目,一般情況下,被 Apache 看中的都不會是爛貨。

我們可以從 http://maven.apache.org/ 下載 Maven 開發包,其實就是一個壓縮包,下載完畢後,解壓一下,配置一下環境變量就可以用了。真是超簡單!

假設我們剛剛下載了一個 apache-maven-3.1.1-bin.zip 文件,現在將其解壓到 D:/tool 目錄下 。我們不妨將解壓後的目錄重命名為 Maven,這樣Maven 的根目錄就是 D:/tool/maven 了。

有兩個環境變量可以配置:

  • M2_HOME = D:/tool/maven

  • MAVEN_OPTS = -Xms128m -Xmx512m

以上 M2_HOME 是必須要配置的,如果想讓 Maven 跑得更快點,可以根據自己的情況來設置 MAVEN_OPTS。

現在我們可以打開 cmd,輸入:

mvn -v

我想您一定會看到一些信息,恭喜您,Maven 安裝成功!

在使用 Maven 之前,很有必要了解一下 Maven 到底是怎樣管理 jar 包的,這就是 Maven 倉庫要幹的活了。

2. 了解 Maven 倉庫

使用 Maven 給我們帶來的最直接的幫助,就是 jar 包得到了統一管理,那麽這些 jar 包存放在哪裏呢?它們就在您的 本地倉庫 中,位於 C:\Users\用戶名\.m2 目錄下(當然也可以修改這個默認地址)。

實際上可將本地倉庫理解“緩存”,因為項目首先會從本地倉庫中獲取 jar 包,當無法獲取指定 jar 包的時候,本地倉庫會從 遠程倉庫(或 中央倉庫) 中下載 jar 包,並放入本地倉庫中以備將來使用。這個遠程倉庫是 Maven 官方提供的,可通過 http://search.maven.org/ 來訪問。這樣一來,本地倉庫會隨著項目的積累越來越大。通過下面這張圖可以清晰地表達項目、本地倉庫、遠程倉庫之間的關系。

技術分享圖片

這個結構是否與 Git 的本地倉庫與遠程倉庫有異曲同工之妙呢?

既然 Maven 安裝了,那麽本地倉庫也就有了,下面我們就一起來創建一個 Maven 項目吧。

3. 創建 Maven 項目

我們不妨創建一個 Java Web 項目,只需在 cmd 中輸入:

mvn archetype:generate

隨後 Maven 將下載 Archetype 插件及其所有的依賴插件,這些插件其實都是 jar 包,它們存放在您的 Maven 本地倉庫中。

在 cmd 中,您會看到幾百個 Archetype(原型),可將它理解為項目模板,您得從中選擇一個。

我們的目標是創建 Java Web 項目,所以您可以選擇 maven-archetype-webapp(可以在 cmd 中進行模糊搜索),隨後 Maven 會與您進行一些對話,Maven 想知道以下信息:

  • 項目 Archetype Version(原型版本號)是什麽?—— 可選擇 1.0 版本

  • 項目 groupId(組織名) 是什麽?—— 可輸入 com.smart

  • 項目 artifactId(構件名)是什麽?—— 可輸入 smart-demo

  • 項目 version(版本號)是什麽?—— 可輸入 1.0

  • 項目 package(包名)是什麽?—— 可輸入 com.smart.demo

以上這種方式稱為 Interactive Mode(交互模式)。

如果您是一位高效人士,或許覺得這樣的交互過於繁瑣,那麽您也可以嘗試僅使用一條命名,來完成同樣的事情:

mvn archetype:generate -DinteractiveMode=false -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.smart -DartifactId=smart-demo -Dversion=1.0

以上這種方式成為 Batch Mode(批處理模式)。

當然,還有第三種選擇,使用 IDE 來創建 Maven 項目,您可以使用 Eclipse、NetBeans、IDEA 來創建 Maven 項目,操作過程應該是非常簡單的。

您也可以使用 IDEA 直接打開一個 Maven 項目,只需要 File -> Open -> 選擇 pom.xml,那麽下面您就可以在 IDEA 中開發 Maven 項目了,貼一張圖片吧:

技術分享圖片

其實這個目錄結構還不太完備,我們需要手工添加幾個目錄上去,最終的目錄結構看起來是這樣的:

技術分享圖片

我們手工創建了三個目錄:

  1. src/main/java

  2. src/test/java

  3. src/test/resources

為什麽自動生成的目錄不完備?確實挺無語的,我們就不要去糾結了。不過有必要稍微解釋一下這個 Maven 目錄規範:

  • main 目錄下是項目的主要代碼,test 目錄下存放測試相關的代碼。

  • 編譯輸出後的代碼會放在target 目錄下(該目錄與 src 目錄在同一級別下,這裏沒有顯示出來)。

  • java 目錄下存放 Java 代碼,resources 目錄下存放配置文件。

  • webapp 目錄下存放 Web 應用相關代碼。

  • pom.xml 是 Maven 項目的配置文件。

其中 pom.xml 稱為 Project Object Model(項目對象模型),它用於描述整個 Maven 項目,所以也稱為 Maven 描述文件。

可見 pom.xml 才是理解 Maven 的關鍵點,很有必要看看它到底長什麽樣。

4. 理解 pom.xml

當 您打開自動生成的 pom.xml,或許會感覺到可讀性不太好,有必要做一下格式化,經過整理後是這樣的:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.smart</groupId>
    <artifactId>smart-demo</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>

    <name>smart-demo Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>smart-demo</finalName>
    </build>

</project>

從上往下簡要說明一下:

  • modelVersion:這個是 POM 的版本號,現在都是 4.0.0 的,必須得有,但不需要修改。

  • groupId、artifactId、version:分別表示 Maven 項目的組織名、構件名、版本號,它們三個合起來就是 Maven 坐標,根據這個坐標可以在 Maven 倉庫中對應唯一的 Maven 構件。

  • packaging:表示該項目的打包方式,war 表示打包為 war 文件,默認為 jar,表示打包為 jar 文件。

  • name、url:表示該項目的名稱與 URL 地址,意義不大,可以省略。

  • dependencies:定義該項目的依賴關系,其中每一個 dependency 對應一個 Maven 項目,可見 Maven 坐標再次出現,還多了一個 scope,表示作用域(下面會描述)。

  • build:表示與構建相關的配置,這裏的 finalName 表示最終構建後的名稱 smart-demo.war,這裏的 finalName 還可以使用另一種方式來定義(下面會描述)。

如果用樹形圖來表達 pom.xml,那麽會更加清晰:

技術分享圖片

可見,除了項目的基本信息(Maven 坐標、打包方式等)以外,每個 pom.xml 都應該包括:

  1. Lifecycle(生命周期)

  2. Plugins(插件)

  3. Dependencies(依賴)

Lifecycle 是項目構建的生命周期,它包括 9 個 Phase(階段)。

大家知道,Maven 是一個核心加上多個插件的架構,而這些插件提供了一系列非常重要的功能,這些插件會在許多階段裏發揮重要作用。

階段 插件 作用
clean clean 清理自動生成的文件,也就是 target 目錄
validate 由 Maven 核心負責 驗證 Maven 描述文件是否有效
compile compiler、resources 編譯 Java 源碼
test compiler、surefire、resources 運行測試代碼
package war 項目打包,就是生成構件包,也就是打 war 包
verify 由 Maven 核心負責 驗證構件包是否有效
install install 將構件包安裝到本地倉庫
site site 生成項目站點,就是一堆靜態網頁文件,包括 JavaDoc
deploy deploy 將構件包部署到遠程倉庫


以上表格中所出現的插件名稱實際上是插件的別名(或稱為前綴),比如:compiler 實際上是 org.apache.maven.plugins:maven-compiler-plugin:2.3.2,這個才是 Maven 插件的完全名稱。

每個插件又包括了一些列的 Goal(目標),以 compiler 插件為例,它包括以下目標:

  • compiler:help:用於顯示 compiler 插件的使用幫助。

  • compiler:compile:用於編譯 main 目錄下的 Java 代碼。

  • compiler:testCompile:用於編譯 test 目錄下的 Java 代碼。

可見,插件目標才是具體幹活的人,一個插件包括了一個多個目標,一個階段可由零個或多個插件來提供支持。

我們可以在 pom.xml 中定義一些列的項目依賴(構件包),每個構件包都會有一個 Scope(作用域),它表示該構件包在什麽時候起作用,包括以下五種:

  1. compile:默認作用域,在編譯、測試、運行時有效

  2. test:對於測試時有效

  3. runtime:對於測試、運行時有效

  4. provided:對於編譯、測試時有效,但在運行時無效

  5. system:與 provided 類似,但依賴於系統資源

可用一張矩陣表格來表示:

作用域 編譯時有效 測試時有效 運行時有效 示例
compile smart-framework.jar
test junit.jar
runtime mysql-connector-java.jar
provided servlet-api.jar
system JDK 的 rt.jar


如果您想開發一個 Smart 應用,可參考如下 p om.xml:

 1 <project xmlns="http://maven.apache.org/POM/4.0.0"
 2          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
 4          http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5 
 6     <modelVersion>4.0.0</modelVersion>
 7 
 8     <properties>
 9         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
10         <smart.version>1.0</smart.version>
11     </properties>
12 
13     <groupId>com.smart</groupId>
14     <artifactId>smart-demo</artifactId>
15     <version>1.0</version>
16     <packaging>war</packaging>
17 
18     <dependencies>
19         <!-- JUnit -->
20         <dependency>
21             <groupId>junit</groupId>
22             <artifactId>junit</artifactId>
23             <version>4.11</version>
24             <scope>test</scope>
25         </dependency>
26         <!-- MySQL -->
27         <dependency>
28             <groupId>mysql</groupId>
29             <artifactId>mysql-connector-java</artifactId>
30             <version>5.1.25</version>
31             <scope>runtime</scope>
32         </dependency>
33         <!-- Servlet -->
34         <dependency>
35             <groupId>javax.servlet</groupId>
36             <artifactId>javax.servlet-api</artifactId>
37             <version>3.0.1</version>
38             <scope>provided</scope>
39         </dependency>
40         <!-- JSTL -->
41         <dependency>
42             <groupId>javax.servlet</groupId>
43             <artifactId>jstl</artifactId>
44             <version>1.2</version>
45             <scope>runtime</scope>
46         </dependency>
47         <!-- Smart -->
48         <dependency>
49             <groupId>com.smart</groupId>
50             <artifactId>smart-framework</artifactId>
51             <version>${smart.version}</version>
52         </dependency>
53     </dependencies>
54 
55     <build>
56         <plugins>
57             <!-- Compile -->
58             <plugin>
59                 <groupId>org.apache.maven.plugins</groupId>
60                 <artifactId>maven-compiler-plugin</artifactId>
61                 <version>2.5.1</version>
62                 <configuration>
63                     <source>1.6</source>
64                     <target>1.6</target>
65                 </configuration>
66             </plugin>
67             <!-- Test -->
68             <plugin>
69                 <groupId>org.apache.maven.plugins</groupId>
70                 <artifactId>maven-surefire-plugin</artifactId>
71                 <version>2.15</version>
72                 <configuration>
73                     <skipTests>true</skipTests>
74                 </configuration>
75             </plugin>
76             <!-- Package -->
77             <plugin>
78                 <groupId>org.apache.maven.plugins</groupId>
79                 <artifactId>maven-war-plugin</artifactId>
80                 <version>2.4</version>
81                 <configuration>
82                     <warName>${project.artifactId}</warName>
83                 </configuration>
84             </plugin>
85             <!-- Tomcat -->
86             <plugin>
87                 <groupId>org.apache.tomcat.maven</groupId>
88                 <artifactId>tomcat7-maven-plugin</artifactId>
89                 <version>2.2</version>
90             </plugin>
91         </plugins>
92     </build>
93 
94 </project>

以上 pom.xml 大致解釋一下:

  • 我們可使用 properties 來定義一些配置屬性,例如:project.build.sourceEncoding(項目構建源碼編碼方式),可設置為 UTF-8,可防止中文亂碼。也可定義相關構件包版本號,例如:smart.version,便於日後統一升級。

  • 建議使用最新版本的 JUnit,通過 Archetype 自動生成的 JUnit 太老了(3.8.1),可改為最新版(4.11)。

  • 因為沒必要使用 MySQL 客戶端的 API,它僅僅在運行時有效,所以我們將 MySQL 構件包的作用域設置為 runtime。

  • 因為我們只想在代碼中使用 Servlet API,而不想將它所對應的 jar 包放入 WEB-INF 的 lib 目錄下,所以我們可設置 Servlet 構件包的作用域為 provided。

  • 為了保證在 JDK 1.6 運行,我們可配置 maven-compiler-plugin 插件,設置輸入源碼為 1.6,編譯輸出的字節碼也為 1.6。

  • 如果想跳過測試,可配置 maven-surefire-plugin 插件,將 skipTests 設置為 true。

  • 如果想配置生成的 war 包為 artifactId,可修改 maven-war-plugin 插件,將 warName 修改為 ${project.artifactId},這樣就無需再配置 finalName 了。

  • 如果想通過 Maven 將應用部署到 Tomcat 中,可使用 tomcat7-maven-plugin 插件,可使用 mvn tomcat7:run-war 命令來運行 war 包。

5. 使用 Maven 命令

前面我們已經使用了幾個 Maven 命令,例如:mvn archetype:generate,mvn tomcat7:run-war 等。其實,可使用兩種不同的方式來執行 Maven 命令:

方式一:mvn <插件>:<目標> [參數]

方式二:mvn <階段>

現在我們接觸到的都是第一種方式,而第二種方式才是我們日常中使用最頻繁的,例如:

  • mvn clean:清空輸出目錄(即 target 目錄)

  • mvn compile:編譯源代碼

  • mvn package:生成構件包(一般為 jar 包或 war 包)

  • mvn install:將構件包安裝到本地倉庫

  • mvn deploy:將構件包部署到遠程倉庫

執行 Maven 命令需要註意的是:必須在 Maven 項目的根目錄處執行,也就是當前目錄下一定存在一個名為 pom.xml 的文件。

6. 後記

Maven 使 Java 開發更加規範化與自動化,其實 Maven 那點事遠遠不止這些,如果您掌握了以上這些基礎知識,再去學習 Maven 的高級特性,我想一定會是一件非常輕松的事情。

推薦大家使用 OSC Maven,它是國內 Maven 的鏡像站點,使用它可加快構件包的下載速度,從而提升您的開發效率,可閱讀《使用 OSC Maven 倉庫》這篇文章來學會如何使用 OSC Maven。

感謝您閱讀本文,感謝您對“Java 那點事兒”與“Smart Framework”的支持與鼓勵!

轉載自:黃勇

如果你對MVEN有更多的疑問請訪問:https://stackoverflow.com/questions/14144085/maven-failed-to-resolve-dependencies-javax-activation

Maven 那點事兒(轉)