一个跨平台的项目管理及自动构建工具
Maven
Maven是一个跨平台的项目管理及自动构建工具,主要服务于Java平台,基于项目对象模型(Project Object Model ,缩写:POM),通过一段描述信息来管理一个项目的构建、报告和文档等步骤。1
优点
- 通用项目结构
- 模块化设计
- 集中式依赖管理
- 更少的决策,使开发人员专注于软件开发的核心工作,由Maven管理依赖,处理构建发布2
安装(可选)
-
JDK环境
-
设置环境变量
MAVEN_HOME C:\Program Files\apache-maven-3.6.1 path %MAVEN_HOME%\bin # 设置JVM的最小和最大内存,可选 MAVEN_OPTS -Xms128m -Xmx512m
-
验证
cmd命令行,输入
mvn -v
IDE已经自带Maven,位置为C:\Program Files\JetBrains\IntelliJ IDEA 2019.1.3\plugins\maven\lib\maven3
。
Maven目录结构
+-- bin/ ---mvn的运行脚本
+-- boot/ ---类加载器框架
+-- conf/ ---配置文件
| --- settings.xml ---全局配置文件
| --- ...
+-- lib/ ---Maven运行时所需要的java类库
--- ...
Maven的settings.xml配置文件包含两处:全局配置${M2_HOME}/conf/settings.xml
和用户配置${user.home}/.m2/settings.xml
。
配置优先级局部配置优先于全局配置,从高到低:pom.xml> user settings > global settings。
Maven项目目录结构
约定优于配置,Maven项目的目录约定如下所示3:
+--project ---工程目录
| +-- src ---源代码目录
| | +-- main
| | | +-- java ---Java文件
| | | | --- ...
| | | +-- resources ---资源文件(如:配置文件)
| | | | --- ...
| | | +-- webapp ---Web工程主目录
| | | | +-- WEB-INF
| | | | | --- web.xml
| | | | --- ...
| | +-- test ---测试目录
| | | +-- java
| | | +-- resources
| +-- target ---编译后目标文件输出位置
| --- pom.xml ---Maven项目核心配置文件
| --- ...
生命周期和插件
Maven的生命周期就是对所有的构建过程进行抽象和统一。生命周期本身不做任何实际的工作,实际的任务(如:编译源代码)都交由插件来完成。每个构建步骤都可以绑定一个或者多个插件行为,而且Maven为大多数构建步骤编写并绑定了默认插件。
依赖管理
-
构件6
任何一个依赖、插件或者项目构建的输出,都可以称之为构件。
-
坐标
Maven依赖使用Maven坐标来定位,而Maven坐标主要由GAV(groupId,artifactId,version)构成。
-
依赖范围
Maven有三套classpath:编译classpath、测试classpath和运行classpath,执行不同生命周期操作时classpath不同。scope选项的值决定该依赖构件会被引入到哪个classpath中。
- compile:对编译、测试、运行三种classpath都有效,为默认值
- test:只对测试有效,在编译和运行时将无法使用该类依赖,如:junit
- provided:编译和测试有效,运行无效,如:容器提供的servlet-api
- runtime:测试和运行有效,编译无效,如:jdbc驱动
- system:系统依赖范围,如:Maven中央仓库没有的第三方Jar
- import:导入依赖范围
-
依赖传递
A依赖B,而B又依赖C,A对C的依赖就是传递依赖。我们只需要引入A构件的依赖,Maven会自动为我们引入其依赖及传递依赖。
-
依赖冲突
当多个传递性依赖中有对同一构件不同版本的依赖产生冲突时:
- 短路优先,优先解析路径短的版本
- 先声明先优先,如果路径长度相同,则谁先声明,先解析谁
-
依赖排除
使用exclusions。
-
依赖聚合7
父子工程,同一个项目中包含很多模块,使用一个外部的pom文件统一管理。
-
依赖继承
属性继承,dependencyManagement和pluginManagement管理的依赖和插件不需要写版本号。
配置
-
settings.xml详解8
-
pom.xml详解9
-
修改本地仓库默认位置
settings.xml放开注释
<localRepository>路径</localRepository>
。 -
设置使用阿里云仓库10
pom.xml文件添加
<!-- 设置Maven仓库为阿里云 --> <repositories> <repository> <id>aliyun-repos</id> <name>Aliyun Repository</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </repository> <repository> ... </repository> </repositories> <!-- 设置Maven插件仓库为阿里云 --> <pluginRepositories> <pluginRepository> <id>aliyun-plugin-repos</id> <name>Aliyun pluginRepositories</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </pluginRepository> <pluginRepository> ... </pluginRepository> </pluginRepositories> <!-- 或者通过profile设置仓库为阿里云 -->
或者在settings.xml添加
<mirrors> <!-- 设置默认中央仓库为阿里云 --> <mirror> <id>aliyun-mirror</id> <name>aliyun mirror</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> <mirror> ... </mirror> </mirrors> <!-- 或者通过profile设置仓库为阿里云 -->
Maven项目中依赖的搜索顺序为local_repo>settings_profile_repo>pom_profile_repo>pom_repositories >settings_mirror>central。11
-
设置JDK和编码12
修改pom.xml文件
<!-- JDK和编码设置,JDK版本号为1.7,1.8,1.9,10,11,12 --> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 或 <!-- JDK和编码设置,JDK版本号为1.7,1.8,1.9,10,11,12 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>11</source> <target>11</target> <encoding>UTF-8</encoding> </configuration> </plugin>
或者修改settings.xml,使所有项目生效
<!-- JDK和编码设置,JDK版本号为1.7,1.8,1.9,10,11,12 --> <profile> <id>jdk-1.8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </profile>
-
使用第三方Jar包13
在Intellij idea的Maven窗口或者配置窗口新建Maven install命令将Jar包安装到本地仓库
mvn install:install-file -Dfile=ojdbc10.jar -DgroupId=com.oracle -DartifactId=ojdbc10 -Dversion=10 -Dpackaging=jar #执行完mvn install命令后,Jar包会被安装到本地仓库,之后pom.xml文件可以引用安装好的Jar包
或者通过设置scope为system使用本地库,发布的时候不会复制这个Jar包,使用相对路径时子模块继承依赖存在问题
<!--oracle驱动--> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc10</artifactId> <version>${oracle.driver.version}</version> <scope>system</scope> <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/ojdbc10.jar</systemPath> </dependency>
-
生成源代码和doc文档14
<!-- 生成java source--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <!-- 生成javadoc --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <id>attach-javadocs</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin>
-
跳过测试文件
<!-- 跳过单元测试,但会继续编译--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0-M3</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin>
-
向Maven中央仓库提交Jar包15
-
Eclipse maven使用jibx-maven-plugin插件报Plugin execution not covered by lifecycle configuration error16
-
重命名版本号插件versions-maven-plugin
命令行执行命令
mvn versions:set -DnewVersion=2.0-RELEASE
,或者在Intellij Idea的Maven窗口双击直接执行该命令,然后会让你输入版本号<!-- 重命名版本号 --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-maven-plugin</artifactId> <version>2.7</version> <configuration> <!-- 是否备份pom文件,用于版本回滚--> <generateBackupPoms>false</generateBackupPoms> </configuration> </plugin>
-
Maven打包生成普通Jar包、可运行Jar包、包含所有依赖的Jar包19
-
使用scope的import属性解决Maven单继承问题20
Nexus私服
Maven仓库分为本地仓库和远程仓库,远程仓库又分为:
-
中央仓库
maven自带的远程仓库,默认地址:http://repol.maven.org/maven2。
-
私服
架设在局域网的一种特殊的远程仓库,目的是代理远程仓库及部署第三方构件。Maven下载构件时,直接请求私服,私服上存在则下载到本地仓库;否则,私服请求外部的远程仓库,将构件下载到私服,再提供给本地仓库下载。
-
其他公共远程仓库
镜像,代替中央仓库,速度快,类似阿里云Maven仓库。
1、安装
下载:官网->Products->OSS Edition->Get Repository OSS21。
启动:Nexus自带Jboss服务器,在%NEXUS_HOME%\nexus-3.12.1-01\bin
目录,执行nexus.exe /run
命令即可启动(执行nexus.exe /install
命令将Nexus注册为系统服务)。
登录:浏览器访问http://localhost:8081/,默认用户名为admin,密码为admin123。
2、Nexus仓库类型
- hosted,本地仓库,通过手动上传或者Maven部署自己的构件或第三方库到这一类型的仓库。
- proxy,代理仓库,用来代理远程公共仓库。
- group,仓库组,用来合并多个hosted/proxy仓库,当项目在多个repository使用资源时就不需要多次引用了,只需要引用一个group即可。
通常会新增hosted类型的库用于手动上传第三方Jar包和proxy类型的库代理阿里云Maven仓库并设置为第一位。
3、Nexus用户权限管理
禁止匿名用户访问后,无法浏览、下载Jar包。
4、Nexus上传下载Jar包Maven配置
设置settings.xml文件
<!-- 配置远程仓库认证信息 -->
<server>
<id>nexus</id>
<username>admin</username>
<password>admin123</password>
</server>
设置pom.xml文件
<!-- 设置Maven仓库为私服(可以通过mirror、profile等方式设置Maven仓库为私服) -->
<repositories>
<repository>
<id>nexus</id>
<name>Nexus</name>
<url>http://192.168.1.102:8081/repository/maven-public/</url>
</repository>
</repositories>
<!-- 部署构件到私服 -->
<distributionManagement>
<repository>
<id>nexus</id>
<url>http://192.168.1.102:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>nexus</id>
<url>http://192.168.1.102:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
<!-- 注意id必须与settings.xml文件中server的id一一对应 -->
pom.xml示例
父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">
<!-- 当前pom版本号 -->
<modelVersion>4.0.0</modelVersion>
<!-- 坐标,由groupId(类似报名,通常为域名反写)、artifactId(模块或构件名)、version、packaging(默认为jar)组成 -->
<groupId>com.ldy</groupId>
<artifactId>parent_project_name</artifactId>
<version>3.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- 子模楷 -->
<modules>
<module>son_project_name</module>
</modules>
<!-- 项目描述信息,inceptionYear为起始年份 -->
<name>这是工程名称</name>
<description>这是工程描述</description>
<url>http://www.lideyu.com</url>
<inceptionYear>2016</inceptionYear>
<!-- 构建环境提前条件 -->
<prerequisites>
<maven>3.0</maven>
</prerequisites>
<!-- 组织 -->
<organization>
<name>丶德灬锅的组织</name>
<url>http://www.lideyu.com</url>
</organization>
<!-- 项目开发人员信息 -->
<developers>
<developer>
<id>ldy</id>
<name>lideyu</name>
<email>ldy@lideyu.com</email>
<url>http://www.lideyu.com</url>
<roles>
<role>开发</role>
</roles>
<timezone>+8</timezone>
</developer>
</developers>
<!-- 项目的其他贡献者列表 -->
<contributors>
<contributor>
<name>xxx</name>
<email>xxx@lideyu.com</email>
<url>http://www.xxx.com</url>
<roles>
<role>contributor</role>
</roles>
<timezone>+8</timezone>
</contributor>
</contributors>
<!-- SCM(Source Control Management)版本库信息 -->
<scm>
<tag>master</tag>
<url>https://code.aliyun.com/lideyu/xxx.git</url>
<connection>scm:git:git@code.aliyun.com:lideyu/xxx.git</connection>
<developerConnection>scm:git:git@code.aliyun.com:lideyu/xxx.git</developerConnection>
</scm>
<!-- 项目的问题管理系统,如Jira -->
<issueManagement>
<system>jira</system>
<url>http://jira.lideyu.com</url>
</issueManagement>
<!--项目持续集成信息 -->
<ciManagement>
<system>jenkins</system>
<url>http://jenkins.lideyu.com</url>
<notifiers>
<notifier>
<type>mail</type>
<address>ldy@lideyu.com</address>
<sendOnError>true</sendOnError>
<sendOnFailure>true</sendOnFailure>
<sendOnWarning>true</sendOnWarning>
<sendOnSuccess>false</sendOnSuccess>
</notifier>
</notifiers>
</ciManagement>
<!--项目相关邮件列表信息-->
<mailingLists>
<mailingList>
<name>tag</name>
<post>post@lideyu.com</post>
<subscribe>subscribe@lideyu.com</subscribe>
<unsubscribe>unsubscribe@lideyu.com</unsubscribe>
<archive>http://archive.lideyu.com</archive>
</mailingList>
<mailingList>
<name>release</name>
<post>post@lideyu.com</post>
<subscribe>subscribe@lideyu.com</subscribe>
<unsubscribe>unsubscribe@lideyu.com</unsubscribe>
<archive>http://archive.lideyu.com</archive>
</mailingList>
</mailingLists>
<!-- licenses信息 -->
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<!-- 项目属性 -->
<properties>
<servlet.version>4.0.1</servlet.version>
<mysql.driver.version>8.0.16</mysql.driver.version>
<mssql.driver.version>7.2.2.jre11</mssql.driver.version>
<oracle.driver.version>10</oracle.driver.version>
<junit.version>4.12</junit.version>
<!-- JDK和编码设置,JDK版本号为1.7,1.8,1.9,10,11,12 -->
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 设置Maven仓库为阿里云 -->
<repositories>
<!--
设置为私服
<repository>
<id>nexus</id>
<name>Nexus</name>
<url>http://192.168.1.102:8081/repository/maven-public/</url>
</repository>
-->
<repository>
<id>aliyun-repo</id>
<name>Aliyun Repository</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</repository>
</repositories>
<!-- 设置Maven插件仓库为阿里云 -->
<pluginRepositories>
<!--
设置为私服
<pluginRepository>
<id>nexus</id>
<name>Nexus</name>
<url>http://192.168.1.102:8081/repository/maven-public/</url>
</pluginRepository>
-->
<pluginRepository>
<id>aliyun-plugin-repo</id>
<name>Aliyun Plugin Repository</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</pluginRepository>
</pluginRepositories>
<!-- 依赖,是真实使用的 -->
<dependencies>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.driver.version}</version>
</dependency>
<!-- mssql驱动 -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>${mssql.driver.version}</version>
</dependency>
<!-- oracle驱动 -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc10</artifactId>
<version>${oracle.driver.version}</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/ojdbc10.jar</systemPath>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 依赖,只是声明,子项目通过version字段可以对其进行继承、覆盖等 -->
<dependencyManagement>
<dependencies>
<!-- c3p0连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.4</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<!-- 产生的构件的文件名,默认值是${artifactId}-${version} -->
<finalName>project_name</finalName>
<!-- 构建产生的所有文件存放的目录,默认为${basedir}/target,即项目根目录下的target -->
<directory>${basedir}/target</directory>
<!-- 插件,是真实使用的 -->
<plugins>
<!-- 与maven-site-plugin插件配合 -->
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- 生成项目站点信息插件 -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
<configuration>
<locales>zh_CN</locales>
</configuration>
</plugin>
<!-- JDK和编码设置,JDK版本号为1.7,1.8,1.9,10,11,12 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- 跳过单元测试,但会继续编译 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<!-- 生成java source -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 生成javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 重命名版本号 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.7</version>
<configuration>
<!-- 是否备份pom文件,用于版本回滚-->
<generateBackupPoms>false</generateBackupPoms>
</configuration>
</plugin>
</plugins>
<!-- 插件,仅仅是一种声明,子项目通过version字段可以对其进行继承、覆盖等 -->
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<!-- 部署构件到私服 -->
<distributionManagement>
<repository>
<id>nexus</id>
<url>http://192.168.1.102:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>nexus</id>
<url>http://192.168.1.102:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
子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">
<parent>
<artifactId>parent_project_name</artifactId>
<groupId>com.ldy</groupId>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>son_project_name</artifactId>
</project>