預期讀者
對 maven 有一定基礎的同學,想對 maven 有系統瞭解的同學
文章思路
本文先會說下 maven 的幾個基本概念:依賴,倉庫,生命週期和插件、
然後是maven 的聚合和繼承、
然後再說 settings 文件和 pom 文件的相關配置、
最後再列出常用插件及使用 maven 遇到的一些問題及解決辦法
第一部分-依賴
傳遞依賴
A–>B–>C 當前項目爲A,A依賴於B,B依賴於C,那麼 A 依賴於 C
依賴範圍
如果 A-> B ,B 依賴於 junit 包,但 B 的 junit 包配置的 <scope>test</scope>
,則 junit 不會被 A 依賴。
常用的依賴範圍有
- compile (默認)
表示被依賴項目需要參與當前項目的編譯,還有後續的測試,運行週期也參與其中,是一個比較強的依賴。打包的時候通常需要包含進去
- test
不會有傳遞依賴,也不會打包,依賴項目僅僅參與測試相關的工作,包括測試代碼的編譯和執行,例如:junit
- provided
參與編譯,測試,運行,但打包的時候不會打進去,如 servlet-api
- runtime
表示被依賴項目無需參與項目的編譯,不過後期的測試和運行週期需要其參與。與compile相比,跳過了編譯而已。例如JDBC驅動,適用運行和測試階段
- system
從參與度來說,和provided相同,不過被依賴項不會從maven倉庫下載,而是從本地文件系統拿。需要添加systemPath的屬性來定義路徑
依賴仲裁
最短路徑原則
A->B->C->common1.1.jar
A->common1.0.jar
那麼A最終會依賴common1.0.jar
加載先後原則
A->B
A->C
B->common1.0.jar
C->common1.1.jar
A同時依賴B和C,那麼B和C誰先加載,就依賴誰的common.jar
排除依賴傳遞
一般用於去除一些無用的依賴,或使用最新的依賴包;如 spring 和 hibernate 都會使用 slf4j ,可以自行決定是用 spring 依賴的,還是用 hibernate 依賴的,或者兩者都不用,使用最新的。
比如spring-core排除commons-loggoing
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
第二部分-倉庫
maven 的倉庫分爲本地倉庫、私服、和遠程倉庫,倉庫中放置的是 jar 包和 插件。
查找方式:本地->私服->遠程
私服對於個人開發是不需要的,但對於團隊開發是必須的;因爲項目肯定會分爲各個模塊,每個人開發的模塊需要部署到私服上去,對方纔能訪問到。
pom 中配置倉庫(個人用或開源項目)
<repositories>
<!--配置阿里雲的倉庫,用於下載常用 jar 包-->
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases><enabled>true</enabled></releases>
</repository>
<!--配置公司倉庫,用於下載其它模塊包-->
<repository>
<id>company</id>
<name>company nexus</name>
<url>http://company/nexus/content/groups/public/</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>true</enabled></snapshots> <!--這個默認是 false 需要自己打開 -->
</repository>
</repository>
<!--配置插件倉庫-->
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>false</enabled></snapshots>
</pluginRepository>
</pluginRepositories>
將倉庫配置到 settings 文件中(公司用項目)
<profiles>
<profile>
<id>repo</id>
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases><enabled>true</enabled></releases>
</repository>
</repositories>
</profile>
<profile>
<id>env-dev</id>
<activation>
<property>
<name>target-env</name>
<value>dev</value>
</property>
</activation>
<properties>
<tomcatPath>/path/to/tomcat/instance</tomcatPath>
</properties>
</profile>
</profiles>
<!--激活屬性配置,可以激活多個-->
<activeProfiles>
<activeProfile>repo</activeProfile>
<activeProfile>env-dev</activeProfile>
</activeProfiles>
將開發的模塊佈置到私服
在 pom 中配置發佈的地址,在 settings 中配置發佈的用戶名和密碼。
pom 配置發佈地址
<distributionManagement>
<repository>
<id>server-rel-id</id> <!--這個 id 需要和 servers 中的 id 一致-->
<name>release-publish</name>
<url>http://company/public</url>
</repository>
<snapshotRepository>
<id>server-rel-id-snapshot</id>
<name>release-publish</name>
<url>http://company/public</url>
</snapshotRepository>
</distributionManagement>
settings 中配置用戶名密碼
<servers>
<server>
<id>server-rel-id</id>
<username>repouser</username>
<password>repopwd</password>
</server>
<server>
<id>server-rel-id-snapshot</id>
<username>repouser</username>
<password>repopwd</password>
</server>
</servers>
常用倉庫
- 阿里雲倉庫
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases><enabled>true</enabled></releases>
</repository>
第三部分-生命週期和插件
maven 的生命週期是抽象的,具體的實現由插件完成。
Maven定義了三套生命週期:clean、default、site,每個生命週期都包含了一些階段(phase)插件的目標 綁定到生命週期的階段來完成任務。三套生命週期相互獨立,但各個生命週期中的phase卻是有順序的,且後面的 phase 依賴於前面的 phase。執行某個phase時,其前面的phase會依順序執行,但不會觸發另外兩套生命週期中的任何phase。
比如執行package,前面的test、comiple等會運行。
clean生命週期
- pre-clean :執行清理前的工作;
- clean :清理上一次構建生成的所有文件(target);
- post-clean :執行清理後的工作
default生命週期
default生命週期是最核心的,它包含了構建項目時真正需要執行的所有步驟。
- process-resources :複製和處理資源文件到target目錄,準備打包;
- compile :編譯項目的源代碼;
- test-compile :編譯測試源代碼;
- test :運行測試代碼;
- package :打包成jar或者war或者其他格式的分發包;
- install :將打好的包安裝到本地倉庫,供其他項目使用;
- deploy :將打好的包安裝到遠程倉庫,供其他項目使用;
site生命週期
- pre-site
- site :生成項目的站點文檔;
- post-site
- site-deploy :發佈生成的站點文檔
插件的目標
一個插件通常可以完成多個任務,每一個任務就叫做插件的一個目標。如執行mvn install命令時,調用的插件和執行的插件目標如下:
將插件綁定到生命週期
Maven的生命週期是抽象的,實際需要插件來完成任務,這一過程是通過將插件的目標(goal)綁定到生命週期的具體階段(phase)來完成的。如:將maven-compiler-plugin插件的compile目標綁定到default生命週期的compile階段,完成項目的源代碼編譯:
舉個例子,使用源碼生成插件,並綁定到 package 階段
<plutins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>jar-no-fork</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
第四部分-maven 的聚合和繼承
聚合是爲了解決模塊的依賴關係,並且方便統一打包和測試。
對於每一個模塊來說,都來寫一遍屬性配置,依賴配置,插件配置,倉庫配置未免太麻煩 ,而且不好管理;所以一般都會有一個父項目來配置好這麼東西,子項目不需要關心jar 版本,插件配置等信息。
一般把聚合和繼承這兩個統一放到一個 pom 文件中,做爲父項目存在,這兩個需要的打包方式爲 pom 。
<!--打包方式需要配置爲 pom -->
<packaging>pom</packaging>
<!-- 聚合的模塊列表,不需要關心順序,maven 會自動根據依賴關係順序-->
<modules>
<module>modul1</module>
<module>modul2</module>
</modules>
<!--配置子項目可能需要用到的 jar 包-->
<dependencyManagement>
<dependencies>
</dependencies>
</dependencyManagement>
<!--配置子項目可能需要用到的 插件-->
<pluginManagement>
<plugins>
</plugins>
</pluginManagement>
最後一部分-常用插件和項目中遇到的一些問題
第三方包的安裝
mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=<packaging>
jdk 版本的問題
因爲 maven 用的 jdk 一般版本都比較老,所以造成老是提示 jdk 版本不對的問題,這樣解決。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
打包時跳過測試
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
mybatis mapper 文件沒有編譯問題
把 mapper xml 文件放到同 mapper 同一級的時候 ,經常用找不到 xml 文件的問題,這樣解決,放到 build 子節點下
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
servlet3 不需要 web.xml 問題
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
常用插件
- 打包帶上源碼,這個其實還挺好用的
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>jar-no-fork</goal></goals>
</execution>
</executions>
</plugin>
- 把java工程打包成爲一個可執行的jar包
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.learn.MyApp</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
- tomcat 插件
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
</configuration>
</plugin>
- jetty 插件
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.2.11.v20150529</version>
<configuration>
<httpConnector>
<port>8081</port>
</httpConnector>
<webAppSourceDirectory>src/main/webapp</webAppSourceDirectory>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webApp>
<contextPath>/sanritools</contextPath>
</webApp>
</configuration>
</plugin>
一點小推廣
Excel 通用導入導出,支持 Excel 公式
https://blog.csdn.net/sanri1993/article/details/100601578
使用模板代碼 ,從數據庫生成代碼 ,及一些項目中經常可以用到的小工具
https://blog.csdn.net/sanri1993/article/details/98664034