Java构建工具对比 🍀
IDE 工具(Eclipse、Net-Beans等编辑器)
- 依赖大量手工操作,编译、测试、打包都是相互独立,很难一键完成;
- 也有可能IDE配置不同,在不同机器上运行结果不一样;
Make (Makefile脚本文件驱动构建)
- 有自定义的语法格式(规则、命令)
- 可以利用系统的本地命令
- 很难实现跨平台构建
- 容易出现语法问题、空格或tab等
Ant (最早用来构建tomcat)
- xml定义构建脚本
- 大量内置的任务是Java实现、保证了跨平台性
- 过程性编译每个项目的执行任务,易造成大量重复(而Maven是声明性、构建过程由插件实现)
- 没有依赖管理,需要借助lvy管理依赖(而Maven内置依赖管理)
Gradle(构建工具(Android app 主要用gradle构建))
- 和Maven 一样 约定大于配置
- 支持多工程构建
- 构建速度快
- 以Groovy语言为基础
Maven 安装目录结构 🍎
bin // mvn 运行脚本、执行Java命令
boot //plexus-classworlds-2.6.0类加载框架,使用该jar加载自己的类库;
conf // 配置文件目录setting
lib // maven 运行时需要的类库
NOTICE.txt // 包含的第三方软件
README.txt // 简要介绍和安装说明
使用 archetype 生成模板 🍓
mvn archetype:generate // 实际是运行 maven-archetype-plugin插件
约定式项目目录结构 🍉
项目
/src
/main 主程序目录 (完成项目功能代码和配置文件)
/java (包相关类定义)
/resources (配置资源文件)
/test
/java
/resources
/pom.xml (maven配置文件)
Maven的POM.xml文件 🌞
Maven是基于项目对象模型(Project Object Model,POM)的概念,用来管理项目的依赖以及项目的编译等功能
<?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.test</groupId>
<artifactId>MavenTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>MavenTest</name>
</project>
- 第一行是XML头,指定了该xml文档的版本和编码方式;
- project 是根元素,声明了一些POM相关的命名空间及xsd元素;
- modelVersion指定了当前POM的版本,在 maven2和maven3 都是 4.0.0;
- groupId定义了项目属于哪个组织,通常是组织域名的倒序,比如说我的域名是 test.com,所以groupId就是 com.test;
- artifactId定义了项目在组织中的唯一ID;
- version指定了项目当前的版本,SNAPSHOT意为快照,说明该项目还处于开发中;
- name 声明项目名称;
注:groupId、artifactId和version这三个元素定义了一个项目的基本坐标,在Maven里任何的jar和pom都是以基于这些坐标进行区分;
Maven命令说明 🌴
-
命令:
mvn clean清理clean:将以前编译得到的旧文件class字节码文件删除(会默认把target文件夹中的数据清理); -
命令:
mvn compile 或 mvn clean compile编译compile:将java源程序编译成class字节码文件(写入target目录中) -
命令:
mvn test 或 mvn clean test测试test:自动测试,自动调用junit程序 -
命令:
mvn report报告report:测试程序执行的结果 -
命令:
mvn package 或 mvn clean package打包package:动态Web工程打War包,java工程打jar包 -
命令:
mvn verifyverify检查包是否有效 -
命令:
mvn install 或 mvn clean install安装install:将包文件安装到本地 Maven 存储库,把被依赖的maven工程的jar包导入到本地仓库中;
- 例如 项目A 依赖 项目B ,那么项目B就必须先构建编译安装到本地仓库;
- 通过install插件将项目B构建文件安装复制到本地仓库;
- 命令:
mvn deplop部署deploy:将动态Web工程生成的war包复制到Servlet容器下,使其可以运行,将包文件部署到远程服务器或存储库;
- 查看当前项目已解析依赖
mvn dependency:list
- 查看当前项目依赖树
mvn dependency:tree
- 分析当前项目
// 只会分析编译主代码和测试代码需要用到的依赖,运行时需要的依赖发现不了
mvn dependency:analyze
Maven 坐标描述 🌲
<groudId>com.test</groudId>
<artifactId>test</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
- groudId : 组织唯一标识,一般使用域名反向写法;
- artifactId: 项目的唯一标识;
- version: 版本号
- packaging : maven打包方式(pom/jar/war),默认使用jar
- pom 父类型一般为pom类型,pom是指项目里没有java代码,也不执行任何代码,只是为了聚合工程或传递依赖用;在执行maven命令的时候将首先对父项目执行,然后当 父项目 的packing 类型为 pom 时,将对其所有的子模块执行同样的命令,否则无法执行同样命令,以及依赖的传递将无法由maven 编译或打包;
- jar 内部调用或作为服务包;
- war 打包项目用于Web容器上部署(tomcat/Jetty等)
- classifier: 用来帮助定义构建生成一些附属构件、需要附加插件帮组生成;
- type:指定了依赖的类型,默认为 jar;
- scope:指定了依赖的范围;
- optional:标记了依赖是否是可选的(针对 传递性依赖设置是否可选);
- exclusions:用来排除传递性依赖;
比如:
A 依赖=>B 依赖=> C,不要引入传递性依赖C,可以使用 exclusions中含exclusion加入排除的groupdId和artifactId不需要version;
<dependency>
<groupId>com.test</groupId>
<artifactId>project-b</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>com.test</groupId>
<artifactId>project-c</artifactId>
</exclusion>
</exclusions>
</dependency>
提示:
<dependency></dependency>内部通过依赖的基本坐标groupId、artifactId、version确定唯一的依赖,可以称这3个为坐标;
依赖范围scope详解 🌳
-
1、compile: 默认值,适用于所有阶段(开发、测试、部署、运行),本jar会一直存在所有阶段;
-
2、provided:只在开发、测试阶段使用,目的是不让Servlet容器和你本地仓库的jar包冲突;
-
3、runtime: 只在运行时使用,如JDBC驱动,适用运行和测试阶段。
-
4、test: 只在测试时使用,用于编译和运行测试代码。不会随项目发布。
-
5、system: 类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它。
-
compile,默认的依赖范围,表示依赖需要参与当前项目的编译,测试、运行周期;
-
test,表示依赖仅参与测试,包括测试代码的编译和运行。比如: junit;
-
runntime,表示依赖无需参与到项目的编译,不过后期的测试和运行需要,比如: jdbc驱动;
-
provided,表示不打包进去,别的容器会提供或编译与测试环境要求需要 比如: servlet-api;
-
system,从参与程度上来说,和 provided 类似编译与测试 ,但不通过 Maven 仓库解析,可能会造成构建的不可移植,要谨慎使用;
-
import,导入依赖范围;
依赖传递性 🔥
Maven 会解析直接依赖的POM,将那些必要的间接依赖,以传递性依赖形式引入到当前项目中;
test-demo(一级) 依赖=> spring-boot-starter-web(二级) 依赖=> spring-webmvc (三级)
- test-demo 有一个compile依赖范围的spring-boot-starter-web依赖;
- spring-boot-starter-web有一个compile依赖范围的spring-webmvc;
- spring-webmvc 是test-demo 的传递性依赖;
- 传递性依赖的依赖范围由 一级和二级依赖的依赖范围决定(都是compile,则传递性依赖范围为compile);
- 三级如果是可选依赖,就不会作为一级的传递性依赖并不造成影响;只会对二级造成影响;
依赖调解(针对多个传递性依赖Maven解析使用哪个,不造成依赖重复) 🌹
- 路径最近优先
- POM中依赖声明顺序最靠前的依赖优先;
统一依赖版本声明(properties元素) 🍏
为了统一管理版本号,可以使用properties标签,里面可以自定义版本的标签名;在使用的地方使用${自定义标签名};
- 可以定义变量在dependency中引用,代码如下所示:
<properties>
<java.version>1.8</java.version>
<spring-framework.version>4.3.18.RELEASE</spring-framework.version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
仓库描述 💐
本地仓库
- 默认路径: .m2/repository/
- 本地项目只有在本地仓库内,才能给其他maven项目使用;
私服(远程仓库)
- 拉取的依赖坐标当私服没有时,就会去中央仓库去拉取;
- 私服认证
- settings配置
<servers>
<server>
<id>jboss</id>
<username>user</username>
<password>pwd</password>
</server>
</servers>
- 部署构件到私服 (1) POM配置distributionManagement
<project>
<distributionManagement>
<repository><!--发布版本构件仓库-->
<id>maven-releases</id> <!--与Settings中server配置ID匹配 -->
<name>maven Release Repository</name>
<url>http://192.168.0.12/repository/maven-releases/</url>
</repository>
<snapshotRepository><!--开发版本构件仓库-->
<id>maven-snapshots</id>
<name>maventSnapshots Repository</name>
<url>http://192.168.0.12/repository/maven-snapshot/</url>
</snapshotRepository>
</distributionManagement>
</project>
(2) 配置完成,运行 mvn clean deploy项目构建的构件部署到私服
中央仓库 (central)
- 可在maven-core-3.8.4.jar\org\apache\maven\repository\RepositorySystem.class 中查看仓库地址;
- 配置POM中使用远程仓库
<project>
<repositories>
<id>jboss</id><!--仓库ID必须唯一-->
<name>jboss Name</name>
<url>http://repository.jboss.com/maven2/</url>
<release>
<enabled>true</enabled> <!--支持下载发布版-->
<checksumPolicy>fail</checksumPolicy><!--当Maven验证构件校验文件失败时处理:-ignore(忽略),fail(失败),或者warn(警告)-->
<updatePolicy>daily</updatePolicy> <!--从远程仓库检查更新频率,daily表示每天检查一次、never从不检查更新、always每次构建都检查更新、interval 间隔检查更新-->
<!--如果坐标一致,maven不会更新-->
</release>
<snapshots>
<enabled>false</enabled><!--不支持下载开发版-->
</snapshots>
<layout>default</layout>
</repositories>
</project>
- 为什么区分发布版和开发版?
(1)因为发布版固定版本号不是用于开发频繁更新,来频繁修改POM;
(2)使用开发版如1.0.SNAPSHOT ,发布的时候Maven 会自动打上时间戳;
(3)开发版每次检查更新时就会安装最新时间的开发包,可以通过配置updatePolicy和使用命令
mvn clean isntall -U,-U 强行检查更新;
- 配置远程仓库镜像地址(阿里云) 修改在conf/settings.xml下添加镜像仓库地址
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
mirrorOf 使用介绍说明(Maven自带的中央仓库使用的仓库id为central)
-
<mirrorOf>*<mirrorOf>表示匹配所有远程仓库; -
<mirrorOf>external:*<mirrorOf>表示匹配所有远程仓库,使用localhost、file://协议的除外,既匹配不在本机上的远程仓库; -
<mirrorOf>central,central1<mirrorOf>表示匹配仓库central和central1,使用逗号分隔多个远程仓库; -
<mirrorOf>*,!central<mirrorOf>表示匹配所有远程仓库,central除外,使用感叹号将指定仓库从匹配中排除;
注: 镜像仓库会完全遮蔽被镜像的仓库,当镜像仓库不稳定,则无法下载构件;
生命周期和插件 🍄
初始化、编译、测试、打包、集成测试、部署;
三种独立生命周期(互不影响)
- clean 清理项目 (如下阶段)
- pre-clean 清理前工作
- clean 清理上一次构建的文件
- post-clean 清理后工作
- default 构建的核心部分,编译,测试,打包,部署等等(如下阶段)
- validate
- initialize
- generate-sources
- process-sources 处理项目主资源文件(src/main/resource)
- generate-resource
- process-resource
- compile 编译项目的主源码(src/main/java)
- process-classes
- generate-test-sources
- process-test-sources 处理项目测试源码文件
- generate-test-resource
- process-test-resource
- test-compile 编译项目测试代码(src/test/java)
- process-test-classes
- test 使用单元测试框架
- prepare-package
- package 接受编译好的文件,打包jar等
- pre-integration-test
- integration-test
- post-integration-test
- verify
- install 包安装到本地仓库
- deploy 包复制到远程仓库 文档详解
- Site Lifecycle 生成项目报告,站点,发布站点。
- pre-site 执行一些需要在生成站点文档之前完成的工作
- site 生产项目站点文档
- post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
- site-deploy 将生成的站点文档部署到特定的服务器上
注:例如 命令mvn clean install实际执行是pre-clean和clean阶段,而default生命周期是validate至install阶段,两个生命周期阶段结合;
maven插件 官网插件
- 编译插件 maven-compiler-plugin
Maven提供了编译插件,可在编译插件中设置Java的编译级别,代码如下:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
-
测试插件 maven-surefire-plugin
-
描述插件 maven-help-plugin
// 插件信息
mvn help:describe -Dplugin=org.springframework.boot:spring-boot-maven-plugin
// 插件目标信息
mvn help:describe -Dplugin=org.springframework.boot:spring-boot-maven-plugin -Dgoal=run
-
maven-shade-plugin生产可执行jar包
-
maven-surefire-plugin 介绍
- Maven本身并不是一个单元测试框架,在构建执行到特定生命周期阶段的时候,通过插件来执行JUnit或者TestNG的测试用例;
- 测试运行器(Test Runner),它能兼容JUnit 3、JUnit 4以及TestNG,自动执行测试源码路径(默认为src/test/java/;
Test*.java:任何子目录下所有命名以Test开关的Java类;
Test.java:任何子目录下所有命名以Test结尾的Java类;
- 要想跳过测试,在命令行加入参数skipTests如:
mvn package -DskipTests
- 需要跳过测试运行,还要跳过测试代码的编译
mvn package -Dmaven.test.skip=true
- 动态指定要运行的测试用例
// 可以使用逗号定多个测试类:
mvn test -Dtest=Random*Test,AccountCaptchaServiceTest
- 可以添加-DfailIfNoTests=false参数告诉maven-surefire-plugin即使没有任何测试也不要报错
mvn test -Dtest -DfailIfNoTests=false
- maven-compiler-plugin
- maven-compiler-plugin 插件来对 Java 代码编译的,如果不指定 JDK 版本,maven-compiler-plugin 会自动使用一个默认的版本;
- maven-compiler-plugin 默认的 JDK 版本为 1.7,此时 JDK 1.7 是不可能将带有 JDK 1.8 特性的代码编译通过的
指定jdk 版本
<?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>cn.test</groupId>
<artifactId>testDemo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<!-- maven-compiler-plugin 将会使用指定的 JDK 版本对源代码进行编译(针对编译运行环境) -->
<maven.compiler.source>1.8</maven.compiler.source>
<!-- maven-compiler-plugin 将会使用指定的 JDK 版本将 java 文件编译为 class 文件(针对编译运行环境)-->
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
聚合 🍉
(父)聚合模板,打包方式<packaging>pom</packaging>必须为pom,否则无法构建
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>test-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Test Demo</name>
<modules> <!-- 子模块-->
<module>test-name1</module>
<module>test-name2</module>
</modules>
</project>
继承 🍎
POM元素
- groupId
- version
- description
- organization
- inceptionYear
- url
- developers
- contributors
- distributionManagement 项目部署配置
- properties 自定义属性
- dependencys
- dependencyManagement 项目依赖管理配置
- repositories 仓库配置
- build
- reporting
关于dependencyManagement说明
- 因dependencies默认会被子项目继承;
- dependencyManagement 只是声明依赖,并不自动实现引入,子项目需要显示声明需要的依赖;
- 项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;
- 如果子项目中指定了版本号,那么会使用子项目中指定的jar版本;
- 使用import依赖范围(type:pom)可以将目标pom中dependencyManagement导入合并到当前依赖管理配置dependencyManagement;
关于pluginManagement配置管理插件
子模块声明使用的插件,会继承父模块pluginManagement配置,统一管理配置和版本;
<!-- 父POM-->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- 源代码编译版本 -->
<source>1.8</source>
<!-- 目标平台编译版本 -->
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<!-- 子POM -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
build配置说明 🍓
配置好build后,执行mvn package之后,会在maven工程指定的target目录里生成配置要求的war包;
<build>
<!-- 项目的名字 -->
<finalName>testDemo</finalName>
<!-- 描述项目中资源的位置 -->
<resources>
<!-- 自定义资源1 -->
<resource>
<!-- 资源目录 -->
<directory>src/main/java</directory>
<!-- 包括哪些文件参与打包 -->
<includes>
<include>**/*.xml</include>
</includes>
<!-- 排除哪些文件不参与打包 -->
<excludes>
<exclude>**/*.txt</exclude>
<exclude>**/*.doc</exclude>
</excludes>
</resource>
</resources>
<!-- 设置构建时候的插件 -->
<plugins>
<!-- 资源插件(资源的插件) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- war插件(将项目打成war包) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1</version>
<configuration>
<!-- war包名字 -->
<warName>testDemo</warName>
</configuration>
</plugin>
</plugins>
</build>
parent 标签的使用
- parent标签,复用依赖,减少冗余配置
- 在多模块(module)的项目中,如此时声明一个父pom文件,将公用的依赖提取到父pom文件中(即使用标签),将大大减少其他子pom文件中的依赖的配置;
<parent>
<groupId>com.test</groupId>
<artifactId>test-parent</artifactId>
<version>1.0.0</version>
</parent>
Maven 属性说明 🍏
内置属性
- ${basedir} 项目根目录包含(pom文件目录)
- ${version} 项目版本
POM 属性
- ${project.build.sourceDirectory} 项目主源码目录(src/main/java)
- ${project.build.testSourceDirectory} 项目测试源码目录(src/test/java/)
- ${project.version} 项目版本
- ${project.outputDirectory} 编译输出目录(target/classes)
自定义属性 properties
<project>
<properties>
<my.name>test</my.name>
</properties>
</project>
Settings属性 用settings开头设置属性
- ${settings.localRepository} 用户本地仓库
java 系统属性 使用
mvn help:system查看所有Java系统属性
环境变量属性 用env开头引用,${env.JAVA_HOME} 指定 JAVA_HOME环境变量值; 使用
mvn help:system查看所有Java系统属性;
Profiles 详解 🔥
- 可以编写于settings和pom上;
- 配置 profile 还可以根据不同的环境(开发环境、测试环境,生产环境)读取不同的配置文件
- 运行指定profile中ID对应的内容,使用mvn 命令后加-P 指定id(多个id用逗号隔开) 如:
mvn clean install -pdev - 资源插件需要配置filtering为true;
<profiles>
<profile>
<div>dev</div>
<properties>
<db.driver>com.mysql.jdbc.Driver</db.driver>
<db.url>jdbc:mysql://localhost:3306/testmysql</db.url>
<db.username>dev</db.username>
<db.password>dev-pwd</db.password>
</properties>
</profile>
<profile>
<div>test</div>
<properties>
<db.driver>com.mysql.jdbc.Driver</db.driver>
<db.url>jdbc:mysql://localhost:3306/testmysql</db.url>
<db.username>test</db.username>
<db.password>test-pwd</db.password>
</properties>
</profile>
</profiles>
- setting 文件中配置profile默认激活状态
<settting>
<activeProfiles>
<activeProfile>dev</activeProfile>
</activeProfiles>
</settting>
- 根据系统属性和设置属性值激活
- 使用
mvn clean install -Dtest=start激活
<profies>
<profile>
<activation>
<property>
<name>test</name>
<value>start</value>
</property>
</activation>
</profile>
</profies>
- 使用根据系统环境激活
<profies>
<profile>
<activation>
<os>
<name>Windows 11</name>
<family>Windows</family> <!--UNIX/Mac-->
<arch>64</arch>
<version></version>
</os>
</activation>
</profile>
</profies>
- 文件存在与否 是否激活
<profies>
<profile>
<activation>
<file>
<exists>test.properties</exists>
</file>
</activation>
</profile>
</profies>
- 默认激活
<profies>
<profile>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profies>
结束
欢迎大家评论,点赞,讨论;