一篇文章帶你搞定JAVA Maven
目錄
- 1、maven是什麼,為什麼存在?專案結構是什麼樣子,怎麼定位jar
- 2、Idea 的操作
- 1.新建maven專案
- 2.配置倉庫
- 3.新增依賴,新增faston的依賴
- 4.打包專案
- 3、Maven座標主要組成
- 4、maven生命週期
- 4.1 名詞解釋
- 4.2 生命週期
- 4.3 goal 的概念
- 4.4 生命週期和phase的關係
- 5、idea maven的配置
- 6、POM有2個很重要的關係:聚合、繼承
- 一、聚合
- 二、繼承
- 7、Maven 中的 profile
- 8、maven 外掛
- 9、環境變數
- 10、Maven 依賴衝突的2個方法
- 1.統一版本
- 2.排除依賴
- 11、scope
- 總結:
1、maven是什麼,為什麼存在?專案結構是什麼樣子,怎麼定位jar
官方說了好多,整的多複雜一樣,簡單說:maven是一個管理包的工具。
MavsxKmFen 存在的必要性是什麼吶?想想開源的jar包如此之多,版本又如此之多,在沒有Maven之前,我們管理jar包全部都是下載之後建立一個lib的資料夾,然後專案進行引用,在其他的專案成員需要修改一個jar的時候需要到處拷貝,在部署的時候也很麻煩,問題存在就要解決,因此出現了Maven,統一管理,統一的倉庫,只需要配置是要哪個版本的包,直接下載就夠了,不用拷貝,是不是很方便。
現在大的問題解決了,怎麼定位一個jar包吶?
2、Idea 的操作
1.新建maven專案
File ->新建->project
勾選從原型(模板)建立,選擇maven-archetype-qiuckstart
填入專案的名字,和groupId (公司域名反過來,如com.alibaba)
選擇本地倉庫的位置,和自定義的setting配置
一路finish,然後等待idea 建立模板專案就好了。
2.配置倉庫
Maven 倉庫有三種類型:
- 本地(local)
- 中央(central)
- 遠端(remote)
當我們執行 Maven 構建命令時,Maven 開始按照以下順序查詢依賴的庫:
步驟 1 - 在本地倉庫中搜索,如果找不到,執行步驟 2,如果找到了則執行其他操作。
步驟 2 - 在中央倉庫中搜索,如果找不到,並且有一個或多個遠端倉庫已經設定,則執行步驟 4,如果找到了則下載到本地倉庫中以備將來引用。
步驟 3 - 如果遠端倉庫沒有被設定,Maven 將簡單的停滯處理並丟擲錯誤(無法找到依賴的檔案)。
步驟 4 - 在一個或多個遠端倉庫中搜索依賴的檔案,如果找到則下載到本地倉庫以備將來引用,否則 Maven 將停止處理並丟擲錯誤(無法找到依賴的檔案)。
阿里雲倉庫配置:
<repositories> <repository> <id>central</id> <name>aliyun maven</name> <url>https://maven.aliyun.com/repository/public/</url> <layout>default</layout> <!-- 是否開啟發布版構件下載 --> <releases> <enabled>true</enabled> </releases> <!-- 是否開啟快照版構件下載 --> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
3.新增依賴,新增fastjson的依賴
舉個例子:
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> </dependency>
4.打包專案
3、Maven座標主要組成
- groupId:組織標識(包名),一般常用公司域名的反序,比如com.alibaba
- artifactId:專案名稱,專案的具體名稱
- version:專案的當前版本 ,一般版本號為 大版本.小版本.小版本序號
- packaging:專案的打包方式,最為常見的jar和war兩種
4、maven生命週期
4.1 名詞解釋
lifecycle:生命週期,這是maven最高級別的的控制單元,它是一系列的phase組成,也就是說,一個生命週期,就是一個大任務的總稱,不管它裡面分成多少個子任務,反正就是執行一個lifecycle,就是交待了一個任務,執行完後,就得到了一個結果,中間的過程,是phase完成的,自己可以定義自己的lifecycle,包含自己想要的phase
phase:可以理解為任務單元,lifecycle是總任務,phase就是總任務分出來的一個個子任務,但是這些子任務是被規格化的,它可以同時被多個lifecycle所包含,一個lifecycle可以包含任意個phase,phase的執行是按順序的,一個phase可以繫結很多個goal,至少為一個,沒有goal的phase是沒有意義的
goal: 這是執行任務的最小單元,它可以繫結到任意個phase中,一個phase有一個或多個goal,goal也是按順序執行的,一個phase被執行時,繫結到phase裡的goal會按繫結的時間被順序執行,不管phase己經綁定了多少個goal,你自己定義的goal都可以繼續綁到phase中
mojo: lifecycle與phase與goal都是概念上的東西,mojo才是做具體事情的,可以簡單理解mojo為goal的實現類,它繼承於AbstractMojo,有一個execute方法,goal等的定義都是通過在mojo裡定義一些註釋的anotation來實現的,maven會在打包時,自動根據這些anotation生成一些xml檔案,放在plugin的jar包裡
可以通俗理解為lifecyle 是一個公司,phrase 是具體的部門,goal 是一個專案,Mojo 是專案內部的人,其他的都是管理層級,具體的執行還是人。
4.2 生命週期
4.3 goal 的概念
一個goal是獨立的,它可以被繫結到多個phase中去,也可以一個phase都沒有。如果一個goal沒有被繫結到任何一個lifecycle,它仍然可以直接被呼叫,而不是被lifecycle呼叫。
因此可以這樣理解phase與goal的關係:
1.phase其實就是goal的容器。實際被執行的都是goal。phase被執行時,實際執行的都是被繫結到該phase的goal。
2.goal與goal之間是獨立的。因此單獨執行一個goal不會導致其他goal被執行。
goal可以通俗理解為一個專案。
4.4 生命週期和phase的關係
clean生命週期每套生命週期都由一組階段(Phase)組成,我們平時在命令列輸入的命令總會對應於一個特定的階段。比如,執行mvn clean ,這個的clean是Clean生命週期的一個階段。有Clean生命週期,也有clean階段。Clean生命週期一共包含了三個階段:
1.pre-clean 執行一些需要在clean之前完成的工作
2.clean 移除所有上一次構建生成的檔案
3.post-clean 執行一些需要在clean之後立刻完成的工作
"mvn clean" 中的clean就是上面的clean,在一個生命週期中,執行某個階段的時候,它之前的所有階段都會被執行,也就是說,"mvn clean"等同於 mvn pre-clean clean ,如果我們執行 mvn post-clean ,那麼 pre-clean,clean 都會被執行。這是Maven很重要的一個規則,可以大大簡化命令列的輸入
執行phase實際執行的是goal。如果一個phase沒有繫結goal,那這個phase就不會被執行。
<plugin> <groupId>com.mycompany.example</groupId> <artifactId>display-maven-plugin</artifactId> <version>1.0</version> <executions> <execution> <phase>process-test-resources</phase> <goals> <goal>time</goal> </goals> </execution> </executions> </plugin>
一個生命週期包含一些列的步驟,當執行生命週期的時候,會把所有的步驟執行一次
官方文件:
http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
http://maven.apache.org/ref/3.3.9/maven-core/lifecycles.html
5、idea maven的配置
POM 中可以指定以下配置:
- 專案依賴 dependencies
- 外掛 plugins
- 執行目標
- 專案構建 profile
- 專案版本
- 專案開發者列表
- 相關郵件列表資訊
6、POM有2個很重要的關係:聚合、繼承
一、聚合
如果我們想一次構建多個專案模組,那我們就需要對多個專案模組進行聚合
1.聚合配置程式碼
<modules> <module>模組一</module> <module>模組二</module> <module>模組三</module> </modules>
例如:對專案的Hello、HelloFriend、MakeFriends這三個模組進行聚合
<modules> <module>../Hello</module> <module>../HelloFriend</module> <module>../MakeFriends</module> </modules>
其中module的路徑為相對路徑。
二、繼承
繼承為了消除重複的配置,我們把很多相同的配置提取出來,例如:grouptId,version,相同的依賴包等。
繼承配置程式碼:
<parent> <groupId>me.gacl.maven</groupId> <artifactId>ParentProject</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../ParentProject/pom.xml</relativePath> </parent>
Idea 中可以新建一個maven專案,然後刪光資料夾,只留一個pom.xml,然後新增模組,選擇繼承。
7、Maven 中的 profile
- Maven 中有一個概念叫做:profile,它主要是為了解決不同環境所需的不同變數、配置等問題。比如我們內網開發的配置,埠配置等是和生產環境不同的,這個時候就需要區分。
- 有了 profile,可以根據啟用的條件,啟動不同條件下的配置資訊。
- profile 是可以有多個的,也可以同時啟用多個 profile,方便自由組合。
<profiles> <profile> <!--不同環境Profile的唯一id--> <!--開發環境--> <id>dev</id> <properties> <!--profiles.active是自定義的欄位(名字隨便起),自定義欄位可以有多個--> <profiles.active>dev</profiles.active> </properties> </profile> <profile> <!--線上環境--> <id>prod</id> <properties> <profiles.active>prod</profiles.active> </properties> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> </profiles>
Idea 中會顯示配置的兩個profile ,可以選擇啟用
pom檔案裡的配置為
<build> <resources> <resource> <directory>src/main/resources/</directory> <!--先排除掉兩個資料夾--> <excludes> <exclude>dev/*</exclude> <exclude>prod/*</exclude> </excludes> <includes> <!--如果有其他定義通用檔案,需要包含進來--> <!--<include>messages/*</include>--> </includes> </resource> <resource> <!--這裡是關鍵!根據不同的環境,把對應資料夾裡的配置檔案打包--> <directory>src/main/resources/${profiles.active}</directory> </resource> </resources> </build> <profiles> <profile> <!--不同環境Profile的唯一id--> <!--開發環境--> <id>dev</id> <properties> <!--profiles.active是自定義的欄位(名字隨便起),自定義欄位可以有多個--> <profiles.active>dev</profiles.active> </properties> </profile> <profile> <!--線上環境--> <id>prod</id> <properties> <prwww.cppcns.comofiles.active>prod</profiles.active> </properties> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> </profiles>
8、maven 外掛
Maven的核心僅僅定義了抽象的生命週期,具體的任務都是交由外掛完成的。
每個外掛都能實現多個功能,每個功能就是一個外掛目標goal。
Maven的生命週期與外掛目標相互繫結,以完成某個具體的構建任務,例如compile就是外掛maven-compiler-plugin的一個外掛目標。
常用外掛:
maven-antrun-plugin maven-archetype-plugin maven-assembly-plugin maven-dependency-plugin maven-enforcer-plugin maven-help-plugin maven-release-plugin maven-resources-plugin maven-surefire-plugin build-helper-maven-plusxKmFgin exec-maven-plugin jetty-maven-plugin versions-maven-plugin
9、環境變數
${basedir}
表示專案根目錄,即包含pom.xml檔案的目錄;
${version}
表示專案版本;
${project.basedir}
同${basedir};
${project.baseUri}
表示專案檔案地址;
${maven.build.timestamp}
表示專案構件開始時間;
${maven.build.timestamp.format}
表示屬性${maven.build.timestamp}
的展示格式,預設值為yyyyMMdd-HHmm,可自定義其格式,其型別可參考.text.SimpleDateFormat。
${project.build.directory}
表示主原始碼路徑;
${project.build.sourceEncoding}
表示主原始碼的編碼格式;
${project.build.sourceDirectory}
表示主原始碼路徑;
${project.build.finalName}
表示輸出檔名稱;
${project.version}
表示專案版本,與${version}相同;
${project.xxx}
當前pom檔案的任意節點的內容
${env.xxx}
獲取系統環境變數。
${settings.xxx}
指代了settings.xml中對應元素的值。
10、Maven 依賴衝突的2個方法
1.統一版本
使用dependencyManagement 進行版本鎖定,dependencyManagement可以統一管理專案的版本號,確保應用的各個專案的依賴和版本一致。
如果我們專案中只想使用spring core 5.2.0的包,pom.xml可以改為如下
<dependencyManagement> <dependenciehttp://www.cppcns.coms> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.2.0.RELEASE</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2.0.RELEASE</version> </dependency> </dependencies>
2.排除依賴
依賴查詢的兩個原則:
使用路徑近者優先原則:直接依賴級別高於傳遞依賴。
使用第一宣告者優先原則:誰先定義的就用誰的傳遞依賴,即在pom.xml檔案自上而下,先宣告的jar座標,就先引用該jar的傳遞依賴。
Idea 可以安裝maven helper外掛,解決衝突。
maven helper外掛安裝成功,點開pom.xml會發現多了一個Dependency Analyzer檢視,如下上面按鈕的圖示含義如下
Conflicts(檢視衝突)
All Dependencies as List(列表形式檢視所有依賴)
All Dependencies as Tree(樹形式檢視所有依賴)
上圖說明有3個jar存在衝突,點選衝突的jar,可以檢視和哪個jar產生衝突,如下圖
點開pom.xml,切換到Dependency Analyzer檢視,選擇All Dependencies as Tree,點選要排除的jar,右鍵會出現Execlude選項,如下
11、scope
scope取值 | 有效範圍(compile,runtime,test) | 依賴傳遞 | 例子 |
---|---|---|---|
compile | all | 是 | spring-core |
provided | compile,test | 否 | servlet-api |
runtime | runtime,test | 是 | JDBC驅動 |
test | test | 否 | JUnit |
system | compile,test | 是 |
compile :為預設的依賴有效範圍。如果在定義依賴關係的時候,沒有明確指定依賴有效範圍的話,則預設採用該依賴有效範圍。此種依賴,在編譯、執行、測試時均有效。
provided :在編譯、測試時有效,但是在執行時無效。例如:servlet-api,執行專案時,容器已經提供,就不需要Maven重複地引入一遍了。
runtime :在執行、測試時有效,但是在編譯程式碼時無效。例如:JDBC驅動實現,專案程式碼編譯只需要JDK提供的JDBC介面,只有在測試或執行專案時才需要實現上述介面的具體JDBC驅動。
test :只在測試時有效,例如:JUnit。
system :在編譯、測試時有效,但是在執行時無效。和provided的區別是,使用system範圍的依賴時必須通過systemPath元素顯式地指定依賴檔案的路徑。由於此類依賴不是通過Maven倉庫解析的,而且往往與本機系統繫結,可能造成構建的不可移植,因此應該謹慎使用。systemPath元素可以引用環境變數。
總結:
Maven是開發中常用的工具,很重要,所以儘可能的掌握。
本篇文章就到這裡了,希望能給你帶來幫助,也希望您能夠多多關注我們的更多內容!