How Does Maven Work

1.Maven的應用場景

Maven是一個Java平臺下項目管理及自動構建工具,抽象出了Java平臺下的軟件工程構建的標準生命週期,並提供了提供了各個生命週期下的自動化工具。

2.Maven的核心概念

2.1 構建的生命週期(標準順序流程)

Maven對生命週期的抽象是流程順序化的,也就是說你要進行到某個週期的某個階段,那麼這個階段之前的全部階段都會被執行.

2.1.1 clean

清理週期的目的在於去除掉上次構建生成的資源,比如的.class等等,保證構建最後使用的輸出資源是當前工作空間內的處理輸出資源;包含的主要流程:clean

2.2.2 default

默認週期包含了的主要流程:校驗(validate),編譯(compile),測試(test),打包(package),驗證(verify),安裝到本地倉庫(install),發佈到遠程倉庫(deploy)。

2.2.3 site

也叫站點生成周期,主要包括兩個流程:第一生成工程的文檔,第二部署到服務器上去;

2.2 插件

Maven規定了構建週期的每個階段順序執行及某個階段應該幹什麼的標準,也就是完成了對構建流程的抽象並制定了流程的順序標準,那麼這些標準的實現者是誰呢?插件(plugin),插件具體的完成每個流程每個階段的具體的工作。

2.2.1 目標(goal)

一個插件可以有多種功能,每種功能稱之爲一個目標(goal);比如compile插件可以支持編譯功能代碼(goal-compile)和 編譯測試代碼(goal-testCompile);

2.2.2 功能與生命週期的綁定

比如下面的編譯插件提供了compile和testCompile兩個功能,並分別綁定到了default聲明週期的<phase>compile</phase>以及<phase>test-compile</phase>;這就是告訴Maven工具在執行到<phase>compile</phase>和<phase>test-compile</phase>階段時,要去調用maven-compiler-plugin的compile或者testCompile功能。

<plugin>
	<artifactId>maven-compiler-plugin</artifactId>
	<version>2.5.1</version>
	<executions>
		<execution>
			<id>default-compile</id>
			<phase>compile</phase>
			<goals>
				<goal>compile</goal>
			</goals>
			<configuration>
				<source>1.8</source>
				<target>1.8</target>
				<encoding>UTF-8</encoding>
			</configuration>
		</execution>
		<execution>
			<id>default-testCompile</id>
			<phase>test-compile</phase>
			<goals>
				<goal>testCompile</goal>
			</goals>
			<configuration>
				<source>1.8</source>
				<target>1.8</target>
				<encoding>UTF-8</encoding>
			</configuration>
		</execution>
	</executions>
	<configuration>
		<source>1.8</source>
		<target>1.8</target>
		<encoding>UTF-8</encoding>
	</configuration>
</plugin>

2.2.3 mvn命令的基本格式

2.2.3.1 指定聲明週期形式

mvn test:意思是告訴mvn執行到<phasese>test</phasese>,那麼在之前的所有階段及每個階段綁定的每一個goal都會被執行;

2.2.3.2 具體執行插件的功能:

mvn compiler:compile:意思是告訴mvn 值執行這個compiler插件的compile功能,注意這樣只會執行這個插件的這個功能,其他插件的功能不不會執行; 這裏補充一些插件名解析的規則,對於一個插件的名字K,maven會把這個插件名解析成maven-K-plugin(maven自己提供的默認插件)及K-maven-plugin(第三方自定義插件),並從當前工程有效pom.xml的去尋找artifactId(請參看下面的Jar的座標)爲maven-K-plugin或者K-maven-plugin的插件,K就是插件的別名,

2.2.4 生命週期類型

Maven爲不同的類型的工程的每個階段提供了默認的插件來實現約定的功能。 (工程的類型由pom文件的<packaging></packaging> 指定,一般爲jar、war、pom==多 module的情況下)

2.3 Jar的座標

基本上在每一個工程中都不可避免的會加入多個jar作爲lib,而這些lib的中jar的版本兼容性是一個令人相當頭痛的問題:A.jar依賴C.jar,B.jar也依賴C.jar,但是依賴的分別是C的不同版本。

一個兩個還好可以上三者官網上看一下解決下衝突,如果很多這樣的情況,是不是很想死?甚至如果你不是很熟悉每個Jar的話,有衝突你甚至都發現不了。

最好出現一個約定Jar版本管理系統,自動的解決或者提示衝突在哪裏。Maven提供這樣一個系統(包含一個內置的中央倉庫和Jar的座標系)來解決這個問題:

每個Jar必須聲明自己的x(groupId:組織Id)y(artifactId:工程Id)z(version:工程版本)三個座標,使用的依賴也必須明確的聲明其xyz座標,這樣Maven就可以彙總查看整個系統具體使用哪個Jar的哪個版本,如果出現了同Jar不同版本(同XY不同Z)的情況就報告衝突。

2.3.1 衝突的解決機制

這個以後再補充,我一般在衝突的dependency裏面直接exclusion掉,然後重新指定一個較高級的版本。

2.4 倉庫

2.4.1 遠程倉庫

也就是保存全部的Jar的服務器,maven自己提供了一箇中央倉庫,但一般企業開發中都會自己搭建nexus私服。

2.4.2 本地倉庫

也就是下面setting.xml裏面指定的本地路徑。

3.Setting的解釋及解析

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <!--指定你本地倉庫的位置-->
 <localRepository>E:\JarLib</localRepository>
  <!-- 
  是否啓用交互模式:默認true;交互模式是指當maven需要你的輸入時會讀取你在console的輸入的數據
  <interactiveMode>true</interactiveMode>
  -->

  <!-- offline
   是否在離線模式運行?默認false
  <offline>false</offline>
  -->

  <!-- 
   插件組的Id:plugin 的groupId
   內置了 "org.apache.maven.plugins" and "org.codehaus.mojo" ,不需要使用自定插件的人員無需修改
   -->
  <pluginGroups>
    <!-- 
    <pluginGroup>com.your.plugins</pluginGroup>
    -->
  </pluginGroups>

  <!-- 
    網絡代理:默認使用第一個,實際上基本不需要;比如你要去某個特定的倉庫下載Jar而這個倉庫又不在公網需要通過代理去下載,這裏配置代理的安全密碼驗證的東西
   -->
  <proxies>
    <!--  
    <proxy>
      <id>optional</id>
      <active>true</active>
      <protocol>http</protocol>
      <username>proxyuser</username>
      <password>proxypass</password>
      <host>proxy.host.net</host>
      <port>80</port>
      <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
    </proxy>
    -->
  </proxies>

  <!--
	訪問某些服務的票據賬戶密碼或者sshkey等,注意這些Id應該和倉庫的Id一樣,實際上Maven也只會訪問這些服務器
   -->
  <servers>
	<server>
      <id>nexus-private-repo</id>
      <username>admin</username>
      <password>adminpass</password>
    </server>
  </servers>

  <!-- 
  遠程倉庫的鏡像,如果從某個倉庫下載Jar下不下來的時候,比如網絡太垃圾,如果存在這個倉庫的鏡像maven則會轉到這個鏡像來下載。
   -->
  <mirrors>
    <!--  注意mirrodId 必須unique
    <mirror>
      <id>mirrorId</id>
      <mirrorOf>repositoryId</mirrorOf>
      <name>Human Readable Name for this Mirror.</name>
      <url>http://my.repository.com/repo/path</url>
    </mirror>
	-->
  </mirrors>
  <!-- 
	配置項組,在滿足某些條件時激活,配置組中定義的配置會增加到Pom.xml中,這些配置項會被Pom中定義的各個插件使用。一般的都會配置各個工程通用的項目配置及保密的配置等等
  -->
  <profiles>
   <profile>
		<id>nexus-private-repo</id>
		<repositories>
			<!--比如這個倉庫的位置-->
			<repository>
				<id>nexus-private-repo</id>
				<name>nexus-private-repo</name>
				<url>http://127.0.0.1:8090/repository/maven-snapshots</url>
				<releases>
					<enabled>false</enabled>
				</releases>
				<snapshots>
					<enabled>true</enabled>
				</snapshots>
			</repository>
		</repositories>
    </profile>
  </profiles>

  <!--
  激活的profile,會被所有的工程繼承使用,
  -->
  <activeProfiles>
	<activeProfile>nexus-private-repo</activeProfile>
  </activeProfiles>
</settings>

4.pom.xml的一些基本的解釋

<?xml version="1.0" encoding="GBK"?>
<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/xsd/maven-4.0.0.xsd">
  <!--必須聲這一項-->
  <modelVersion>4.0.0</modelVersion>
  <!--多module開發時指定的具體的父POM,父POM的配置大部分都會被繼承-->
  <parent>
    <groupId>com.aruforce</groupId>
    <artifactId>mvn-test</artifactId>
    <version>1.0.0-RELEASE</version>
  </parent>
  <!--下面設定自己的座標系-->
  <groupId>com.aruforce</groupId><!---->
  <artifactId>common</artifactId>
  <version>1.0.1-SNAPSHOT</version>
  <!--設定自己的工程類型-->
  <packaging>Jar</packaging>
  <!--一些配置項目,可以使用${tag}獲取值,注意父POM的中的定義項目不會被繼承下來-->
  <properties>
    <jdk.version>1.8</jdk.version>
    <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <!--jar deploy的遠程倉庫位置-->
  <distributionManagement>
        <repository>
            <id>nexus-private-repo</id>
            <name>Fruit Releases</name>
            <url>http://127.0.0.1:8090/repository/maven-releases</url>
        </repository>
        <snapshotRepository>
            <id>nexus-private-repo</id>
            <name>Fruit Snapshots</name>
            <url>http://127.0.0.1:8090/repository/maven-snapshots</url>
        </snapshotRepository>
    </distributionManagement>
  <!--共用的依賴管理,如果在下面的以來配置中修改其中的配置的話(主要是版本),就是管理中指定的版本-->
  <dependencyManagement>
    <dependencies>
	  <!--junit 插件-->
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
		<!--插件的有效級別:System,provide,test,compile,runtime等等,涉及到插件的依賴傳遞,默認值是compile
		compile:編譯範圍依賴在所有的classpath中可用,同時它們也會被打包。
		provided:provided 依賴只有在當JDK 或者一個容器已提供該依賴之後才使用.已提供範圍的依賴在編譯classpath(不是運行時)可用。它們不是傳遞性的,也不會被打包。
		runtime:runtime 依賴在運行和測試系統的時候需要,但在編譯的時候不需要。比如,你可能在編譯的時候只需要JDBC API JAR,而只有在運行的時候才需要JDBC驅動實現。
		test:test範圍依賴 在一般的編譯和運行時都不需要,它們只有在測試編譯和測試運行階段可用。
		system:system範圍依賴與provided 類似,但是你必須顯式的提供一個對於本地系統中JAR 文件的路徑。不要使用它。
		optional:可選的,classpath有沒有都行。
		-->
        <scope>test</scope>
      </dependency>
    </dependencies>
	<dependency>
		<groupId>com.aruforce</groupId>
        <artifactId>dependA</artifactId>
        <version>1.0.0-RELEASE</version>
        <scope>compile</scope><!--覆蓋上面的配置-->
		<exclusions>
          <exclusion>
             <groupId>com.aruforce</groupId>
			 <artifactId>ABdependC</artifactId><!--依賴1.2.0版本-->
          </exclusion>
        </exclusions>
    </dependency>
	<dependency>
		<groupId>com.aruforce</groupId>
        <artifactId>dependB</artifactId>
        <version>1.0.0-RELEASE</version>
        <scope>compile</scope><!--覆蓋上面的配置-->
		<exclusions>
          <exclusion>
             <groupId>com.aruforce</groupId>
			 <artifactId>ABdependC</artifactId><!--依賴1.0.0版本-->
          </exclusion>
        </exclusions>
    </dependency>
	<dependency>
		<groupId>com.aruforce</groupId>
        <artifactId>ABdependC</artifactId>
        <version>1.2.0-RELEASE</version><!---暫且先試下1.2.0版本如果版本不行就換其他的,都不行git fork modify deploy到nexus 重新引入-->
        <scope>compile</scope>
    </dependency>
  </dependencyManagement>
  <dependencies>
    <dependency>
		<groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>compile</scope><!--覆蓋上面的配置-->
    </dependency>
  </dependencies>
  <!--聲明週期的相關配置-->
  <build>
  	<!--構建過程的通用配置項目-->
    <resources>
      <resource>
        <filtering>${pfile}</filtering>
        <directory>src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
	  	<filtering>false</filtering>
        <directory>src/test/resources</directory>
      </testResource>
    </testResources>
    <finalName>${artifactId}-${version}</finalName>
    <filters>
      <filter>${profile}</filter>
    </filters>
    <plugins>
      <plugin>
	  	<!--關於插件的配置項,可以去插件的官方網站查看使用說明,實際上很少幾乎沒有,長配置的只有編譯插件,及reources插件(主要是根據filrters裏面的配置在打包前處理源配置文件生成不同環境需要的配置)-->
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.5.1</version>
		<configuration>
			<source>1.8</source>
			<target>1.8</target>
			<encoding>UTF-8</encoding>
		</configuration>
      </plugin>
	  <plugin>
        <artifactId>maven-jar-plugin</artifactId>
		<version>2.3</version>
      </plugin>
	  </plugins>
  </build>
  <!--不同配置項 mvn excutable -P profileId 這個profile裏面的配置會生效-->
  <profiles>
    <profile>
      <id>dev</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <pfile>dev.properties</pfile>
      </properties>
    </profile>
	<profile>
      <id>test</id>
      <activation>
        <activeByDefault>false</activeByDefault>
      </activation>
      <properties>
        <pfile>test.properties</pfile>
      </properties>
    </profile>
  </profiles>
</project>

5. 總結

那些安裝配置啊什麼的不值得寫;高級點的需要自己寫插件的部分還沒遇到;插件的配置項目不太應該寫在這裏而且也說明怎麼去查找;依賴的版本版本衝突排解方法也夠簡單粗暴。至於使用說明,讀完也基本上有感覺,自己試着擺弄幾個類型的工程吧 jar->war->多module。。。基本上也就這個學習使用流程吧。。。剩下的私服搭建 一般就是nexus了。。。這個工具的安裝配置。。看看Tutorial什麼也就可以了。。。

開始學習使用maven的時候弄不清楚概念確實很亂很蛋疼。。。總想放棄溜了。。。學完後發現maven這些也是解決特定問題。。。知道問題在哪。。知道運作邏輯後。。看着那些配置項也就明白什麼意思了。。。

吐槽GO語言的一點。。。作爲一個工程導向的語言。。。就一個jar包管理類似的功能。。吹逼這麼長時間都尼瑪要2.0還沒搞完定下來。。。

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