Maven 是java项目的构建和管理工具,主流版本3.x.x,而4.x.x也已更新。五个核心概念:坐标、依赖和仓库,生命周期,插件。
1,基本使用,
学习使用maven还是自己动手从零开始构建,使用集成开发环境会忽略很多细节,导致云里雾里,不知所以。
1.1 创建pom.xml,格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>com.hello</groupId>
<artifactId>hello-world</artifactId>
<version>1.0-SNAPSHOT</version>
<name>hello-world</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.hello.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
1.2 编写代码:
maven约定项目的根目录是pom.xml 文件所在的目录,所以我们在该目录里面创建 :
src/main/java 文件夹来存放java原文件, 注意添加package目录。
src/main/resources 存放配置文件,
src/test/java 存放测试文件
target 存放编译之后的文件。
1.3 mvn clean package 直接编译。编译之后会生成一个jar包,但是jar包不能直接运行,还需要一个插件,来表明main方法入口的位置 需要借助Apache Maven Shade Plugin(https://maven.apache.org/plugins/maven-shade-plugin/usage.html)来完成。
另外可以使用 mvn archetype:generate 来自动生成项目目录结构(骨架),又叫脚手架,有多种项目结构可以选择,根据需要和提示就可以自动生成相应的目录。在运行mvn archetype:generate时,实际上是在运行maven-archetype-plugin插件。插件在maven里面是很重要的概念。
2,maven仓库。
存放依赖包的地方,通过maven坐标(生成项目时定义的groupId,artifactId,version等)来寻找相应的依赖包,分为本地仓库和远程仓库,项目的依赖包maven会首先在本地仓库寻找,如果本地仓库有就直接使用,没有就到远程仓库寻找,并下载到本地仓库使用。
本地仓库的配置在 ~/.m2/setting 中有个标签,标记本地仓库的位置。
<localRepository>~/.m2/repository</localRepository>
远程仓库又分为 *仓库,私服,和其他的公共仓库。maven 有个默认的*仓库:https://repo.maven.apache.org/maven2 。远程仓库的配置,可以在 setting.xml 也可以在pom.xml。
<project>
......
<!-- 配置远程仓库 -->
<repositories>
<repository>
<id>jboss</id>
<name>JBoss Repository</name>
<url>http://repository.jboss.com/maven2/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
<layout>default</layout>
</repository>
</repositories>
......
</project>
但是如果需要认证的话 建议配置在本地的setting文件中: 只需要server.id 与 repository.id 对应的上就可以。
<servers>
<server>
<id>deploymentRepo</id>
<username>repouser</username>
<password>repopwd</password>
</server>
</servers>
还可以将自己开发的项目部署到远程仓库:
<project>
......
<distributionManagement>
<repository>
<id>releases</id>
<name>public</name>
<url>http://59.50.95.66:8081/nexus/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>Snapshots</name>
<url>http://59.50.95.66:8081/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
......
</project>
这里面的 snapshots与 releases跟项目的版本号相关,,如果项目版本号标记为snapshots,每次编译代码时会自动比对远程仓库代码的时间戳,不一致的话 会更新本地仓库依赖,方便协同开发,此所谓快照。
还有一个很重要的概念称之为镜像,如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。也就是说,任何一个可以从仓库Y获得的依赖包,都能够从它的镜像中获取。比如http://maven.aliyun.com/nexus/content/groups/public是阿里提供的*仓库的镜像,
配置在setting.xml 中:
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
mirrorOf的值为central,表示该配置为*仓库的镜像,任何对于*仓库的请求都会转至该镜像。这里的东西比较多,需要使用的话,可以参考文档或者直接搜索引擎解决。
3,maven 生命周期 ,Maven生命周期就是为了对所有的构建过程进行抽象和统一,开发了一套高度完善的、易扩展的生命周期。这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构建步骤。这是一个抽象的概念,可以理解成为整个项目工作的所有阶段(phase)的一个抽象。
4,maven插件,前面说maven的生命周期就是整个项目工作的所有阶段,而且呢它是个抽象的概念,不干活,活就是由插件干的,而且想要干活的话你得跟这个生命周期绑定起来。所以执行 mvn clean 这个生命周期其实是执行的生命周期背后的clean插件,而 mvn clean:clean 也可以实现编译文件全清楚就是这个原因,第一个clean是插件的前缀,而冒号之后的是插件的目标,一个插件可能有多个目标。有些插件是默认绑定在生命周期阶段上的,称之为内置绑定,也可以手动绑定,比如,一下shade插件绑定在 package生命周期上:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration> <!--这个主要是插件的属性配置,跟-D传递参数的效果一样-->
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.jellythink.HelloWorld.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
仔细看phase标签是绑定在package这个阶段(生命周期)上的。还有个命令可以查看maven插件的各种信息:
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-shade-plugin:3.2.1 -Ddetail
5,在maven中,为了支持多环境构建场景,内置了三大特性,即属性、Profile和资源过滤。
5.1 maven属性:
内置属性:${basedir}表示项目根目录,即包含pom.xml文件的目录,${version}表示项目版本。
POM属性:可以使用POM属性引用POM文件中对应元素的值,比如${project.artifactId}就对应了<project><artifactId>元素的值
自定义属性:<properties>标签中定义
Settings属性:可以使用${settings.localRepository}来引用用户本地仓库的地址。
Java系统属性:比如${user.home}指向用户的目录
环境变量属性:所有环境变量都可以使用以env.开头的Maven属性引用。比如${env.JAVA_HOME}指向了JAVA_HOME环境变量的值。我们可以使用mvn help:system查看所有的Java系统属性
5.2 资源过滤,可以将目录里面所有文件的 ${} 占位符替换掉,配置如下:
<build>
<!-- 为主资源目录开启过滤 -->
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<!-- 为测试资源目录开启过滤 -->
<testResources>
<testResource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
</build>
5.3 profile 可以通过 mvn package -Pdev 来激活dev环境对应的配置:
<profiles>
<profile>
<id>dev</id>
<properties>
<db.driver>com.mysql.jdbc.driverClass</db.driver>
<db.url>jdbc:mysql://localhost:3306/dev</db.url>
<db.username>develop</db.username>
<db.password>develop-password</db.password>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<db.driver>com.mysql.jdbc.driverClass</db.driver>
<db.url>jdbc:mysql://localhost:3306/test</db.url>
<db.username>test</db.username>
<db.password>test-password</db.password>
</properties>
</profile>
</profiles>
6,漏掉了一个maven依赖配置:
<project>
...
<dependencies>
<dependency>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<type>...</type>
<scope>...</scope>
<optional>...</optional>
<exclusions>
<exclusion>
...
</exclusion>
</exclusions>
</dependency>
...
</dependencies>
...
</project>
有几个标签值得一记:
scope:(依赖的范围)
compile(默认),
test (只对于测试有效),
provided(对于编译和测试有效,但在运行时无效。最典型的例子是servlet-api),
runtime (对于测试和运行有效,但在编译主代码时无效。最典型的例子就是JDBC驱动实 现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行 项目的时候才需要具体JDBC驱动)
system (此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定)
optional:标记依赖是否可选,
exclusions:用来排除传递性依赖,