Maven
What is Maven?
flowchart TB MR[Maven Repos] LR[Local Repos] RR[Remote Repos] CR[Central Repos] PR[Private Repos] ORR[Others Remote Repos] MR --> LR MR ------>|if local repos doesn't have lib| RR RR ----> CR RR ----> PR RR ----> ORR
- Project Management Tool
- Build Management and Dependencies(管理多個 jar)
Maven Repository
flowchart LR subgraph Center C[(Maven)] end subgraph Left direction TB subgraph App Spring Hibernate Commons_Logging JSON ... end end subgraph Right direction TB subgraph Maven_Central_Repository_Remote_Internet Spring_JAR_files Hibernate_JAR_files ApacheCommons_JAR_files JSON_JAR_files end end Left <====> Center <====> Right
settings.xml
用於設定 Maven 全局配置:
<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
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<usePluginRegistry/>
<offline/>
<pluginGroups/>
<servers/>
<mirrors/>
<proxies/>
<profiles/>
<activeProfiles/>
</settings>LocalRepository
設置本地倉庫的路徑。預設:~/.m2/repository
<localRepository>${user.home}/.m2/repository</localRepository>InteractiveMode
Maven 是否需和用戶交互以獲得輸入:
<interactiveMode>true</interactiveMode>Offline
表示 Maven 是否需要離線模式下運行。由於網路或資安因素,服務器不能連接遠程倉庫時,此配置十分有用。
<offline>false</offline>Servers
類似 username、password 等訊息不應該在 pom.xml,這些訊息可配置在 settings.xml:
<servers>
<server>
<id>server001</id>
<username>my_login</username>
<password>my_password</password>
<privateKey>${usr.home}/.ssh/id_dsa</privateKey>
<passphrase>some_passphrase</passphrase>
<filePermissions>664</filePermissions>
<directoryPermissions>775</directoryPermissions>
</server>
</servers>Mirrors
為倉庫列表配置的下載鏡像列表:
<mirrors>
<mirror>
<id>planetmirror.com</id>
<name>PlanetMirror Australia</name>
<url>http://downloads.planetmirror.com/pub/maven2</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>Proxies
用來配置代理:
<proxies>
<proxy>
<id>myproxy</id>
<active>true</active>
<protocol>http</protocol>
<host>proxy.somewhere.com</host>
<port>8080</port>
<username>proxyuser</username>
<password>somepassword</password>
<nonProxyHosts>*.google.com|ibiblio.org</nonProxyHosts>
</proxy>
</proxies>Dependency
從遠程倉庫下載 jar 到本地,jar 檔之間依賴傳遞。
Scope
| Scope | 說明 | 部署時打包 |
|---|---|---|
compile | 預設值,此 jar 是所有階段需要的 | 是 |
test | 只有在測試時需要使用,如 junit | 否 |
runtime | 只有在運行時需要使用,如 jdbc | 是 |
provided | 期望由 JDK、Tomcat 等來提供,如 servlet.jar | 否 |
system | 由系統提供,需配合 systemPath 使用 | - |
Plugins
maven-compiler-plugin
直接打包,不打包依賴,僅打包 source code 到 JAR 包中:
<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>
<encoding>UTF-8</encoding>
<skipTests>true</skipTests>
<verbose>true</verbose>
<showWarnings>true</showWarnings>
<fork>true</fork>
<meminitial>128m</meminitial>
<maxmem>512m</maxmem>
</configuration>
</plugin>maven-jar-plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>net.arplanets.arc.RSApplication</mainClass>
</manifest>
</archive>
</configuration>
</plugin>maven-dependency-plugin
複製 Project 依賴的所有 jar 包:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>maven-shade-plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<shadedArtifactAttached>true</shadedArtifactAttached>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>maven-assembly-plugin
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>Descriptor 選項:
| 選項 | 說明 |
|---|---|
bin | 類似於預設打包,會將 bin 目錄下的文件打到包中 |
jar-with-dependencies | 會將所有依賴都解壓打包到生成物中 |
src | 只將源碼目錄下的文件打包 |
project | 將整個 project 資源打包 |
maven-surefire-plugin
跳過測試,等同於 mvn package -Dmaven.test.skip:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.6</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>maven-resources-plugin
設置資源文件的編碼方式:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>Build
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/banner.txt</exclude>
<exclude>**/**/spring.factories</exclude>
<exclude>**/*.properties</exclude>
<exclude>**/logback-spring.xml</exclude>
<exclude>**/*.yml</exclude>
</excludes>
</resource>
</resources>
</build>Maven Custom Plugin
package com.example.maven.plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
@Mojo(name = "dependency-counter", defaultPhase = LifecyclePhase.COMPILE)
public class DependencyCounterMojo extends AbstractMojo {
@Parameter(defaultValue = "${project}", required = true, readonly = true)
MavenProject project;
@Parameter(property = "scope")
String scope;
@Override
public void execute() throws MojoExecutionException, MojoFailureeException {
List<Dependency> dependencies = project.getDependencies();
long numDependencies = dependencies.stream()
.filter(d -> (scope == null || scope.isEmpty()) || scope.equals(d.getScope()))
.count();
getLog().info("Number of dependencies: " + numDependencies);
}
}執行 mvn install 後,在 pom.xml 中加入 plugin:
<build>
<plugins>
<plugin>
<groupId>com.app</groupId>
<artifactId>counter-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<goals>
<goal>dependency-counter</goal>
</goals>
</execution>
</executions>
<configuration>
<scope>test</scope>
</configuration>
</plugin>
</plugins>
</build>Maven Scan Extension
生成類似 gradle scan 的報告:
<extensions>
<extension>
<groupId>com.gradle</groupId>
<artifactId>gradle-enterprise-maven-extension</artifactId>
<version>1.11.1</version>
</extension>
</extensions>Private Repository Server
- JFrog Artifactory
- Sonatype Nexus
- Apache Archiva
Benefits
- 新開發人員加入專案更容易
- 容易找到 code、properties files、unit tests、web files 等
- Maven 專案具有可攜性
Deploy
| 類型 | 部署方式 |
|---|---|
| jar | 部署到私有 Nexus Server |
| war | 使用 Maven Cargo 部署到 Tomcat Server,或使用 Jenkins(更強大) |