目前 java 项目流行的项目管理工具 MavenGradle。目前使用率来说,Maven 使用占比是高于 Gradle 的。

Maven 中通过 POM-Project Object Model 项目对象模型的概念来管理项目。在 Maven 中每个项目都相当于一个对象,对象(项目)之间可以依赖、继承、聚合。

项目依赖包查找网站 mvnrepository.com,依赖包放在 Maven 仓库中,我们需要通过依赖的坐标信息,从仓库中下载 jar 。

坐标信息:groupId,artifactId,version

当我们在 pom.xml 引入某个 a.jar , Maven 会从本地仓库查找有没有 a.jar,没有就会去私服下载,私服没有会从中央仓库下载到私服,然后下载本地仓库。

依赖传递

  • maven-a.jar 依赖 maven-b.jar
  • maven-b.jar 依赖 maven-c.jar
  • maven-client 项目中引入 maven-a.jar,那么 maven-b.jarmaven-c.jar 都会引入进来。

    依赖传递遵循的两个规则

    最短路径原则

    有了依赖传递,但也存在一个问题。

    maven-a.jar 依赖 maven-b.jar maven-b.jar 依赖 maven-c.jar(2.0) maven-a.jar 依赖 maven-c.jar(1.0) maven-client 项目中引入 maven-a.jar

最终会采用哪个 maven-c.jar
所以 maven 依赖传递的其中一个规则就是,最短路径原则

a -> b ->c(2.0) a -> c(1.0)

maven-client 项目最终使用 1.0 的 c 。

最先声明原则

最短路径原则存在一个问题,当最短路径一样的时候怎么办,最先声明原则就是再最短路径相同的时候生效。

maven-client 项目中引入 maven-a.jarmaven-b.jar maven-b.jar 只依赖 maven-c.jar(2.0) maven-a.jar 只依赖 maven-c.jar(1.0)

现在依赖的最短路径一样

maven-client -> maven-a -> maven-c(1.0) maven-client -> maven-b -> maven-c(2.0)

maven-client 先引入的 maven-a 那么 maven-c 1.0 生效
maven-client 先引入的 maven-b 那么 maven-c 2.0 生效

最先声明有时达不到我们的预期,我可以可以这样解决:

  • 第一种,打破最短依赖路径,直接在 maven-client 引入你想要的 maven-c 的版本。

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.example</groupId>
    4. <artifactId>maven-a</artifactId>
    5. <version>1.0-SNAPSHOT</version>
    6. </dependency>
    7. <dependency>
    8. <groupId>org.example</groupId>
    9. <artifactId>maven-b</artifactId>
    10. <version>1.0-SNAPSHOT</version>
    11. </dependency>
    12. <dependency>
    13. <groupId>org.example</groupId>
    14. <artifactId>maven-c</artifactId>
    15. <version>1.0-SNAPSHOT</version>
    16. </dependency>
    17. </dependencies>
  • 第二种,排除 jar

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.example</groupId>
    4. <artifactId>maven-a</artifactId>
    5. <version>1.0-SNAPSHOT</version>
    6. </dependency>
    7. <dependency>
    8. <groupId>org.example</groupId>
    9. <artifactId>maven-b</artifactId>
    10. <version>1.0-SNAPSHOT</version>
    11. <exclusions>
    12. <exclusion>
    13. <groupId>org.example</groupId>
    14. <artifactId>maven-c</artifactId>
    15. </exclusion>
    16. </exclusions>
    17. </dependency>
    18. </dependencies>

    依赖作用域

    依赖的作用域定义了 jar 在什么时候生效,打包成 war 或者 jar 的时候是否打包进去。

    1. <dependency>
    2. <groupId>mysql</groupId>
    3. <artifactId>mysql-connector-java</artifactId>
    4. <scope>runtime</scope>
    5. </dependency>

    scope 取值不同,意义不一样。

    compile

    scope 默认取值 compile 标识,当前依赖包,参与项目的编译、运行、测试、打包。

    runtime

    runtime 标识不参与项目编译,参与项目的运行、测试、打包。

    provided

    provided 标识参与项目的编译、运行、测试,但是不参与打包。

    system

    system 用于我们开发的一些二方库,但是不能发布到网上,可以使用这种场景去使用。默认这种 jar 不会打包进去,需要我们配置一下。

参与项目的编译、运行、测试。

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.example</groupId>
  4. <artifactId>maven-d.jar</artifactId>
  5. <version>1.0-SNAPSHOT</version>
  6. <scope>system</scope>
  7. <systemPath>${basedir}/lib/maven-d.jar</systemPath>
  8. </dependency>
  9. </dependencies>
  10. <build>
  11. <plugins>
  12. <plugin>
  13. <groupId>org.springframework.boot</groupId>
  14. <artifactId>spring-boot-maven-plugin</artifactId>
  15. </plugin>
  16. </plugins>
  17. <resources>
  18. <resource>
  19. <directory>${basedir}/lib</directory>
  20. <targetPath>BOOT-INF/lib/</targetPath>
  21. <includes>
  22. <include>**/*.jar</include>
  23. </includes>
  24. </resource>
  25. </resources>
  26. </build>

test

test 标识只在编译测试代码和运行测试代码的时候需要,别的都不用,打包的时候也不会包含。

import

一般我们会在父工程使用这个作用域。表示从其它的 pom.xml 导入 dependency 的配置
比如我们自己的父工程,只想要 springboot 的依赖管理。

  1. <dependencyManagement>
  2. <dependencies>
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-dependencies</artifactId>
  6. <version>${spring-boot.version}</version>
  7. <type>pom</type>
  8. <scope>import</scope>
  9. </dependency>
  10. </dependencies>
  11. </dependencyManagement>

继承和聚合

继承

maven-client 继承了 maven-demo

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project>
  3. <parent>
  4. <artifactId>maven-demo</artifactId>
  5. <groupId>org.example</groupId>
  6. <version>1.0-SNAPSHOT</version>
  7. </parent>
  8. <modelVersion>4.0.0</modelVersion>
  9. <packaging>jar</packaging>
  10. <artifactId>maven-client</artifactId>
  11. </project>

聚合

maven-demo 聚合了五个工程。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project >
  3. <parent>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-parent</artifactId>
  6. <version>2.3.0.RELEASE</version>
  7. <relativePath/> <!-- lookup parent from repository -->
  8. </parent>
  9. <groupId>org.example</groupId>
  10. <artifactId>maven-demo</artifactId>
  11. <packaging>pom</packaging>
  12. <version>1.0-SNAPSHOT</version>
  13. <modules>
  14. <module>maven-a</module>
  15. <module>maven-b</module>
  16. <module>maven-c</module>
  17. <module>maven-client</module>
  18. <module>maven-d</module>
  19. </modules>
  20. </project>
  • 继承用于消除冗余配置,比如一些配置打包配置,配置的变量,项目依赖和插件依赖版本管理
  • 聚合用于快速构建项目。

  • 聚合之前打包 a,b,c,d,clent 需要分别运行 mvn package。

  • 聚合之后,我咱们只需要在 maven-demo 下运行 mvn package。

生命周期

maven 内部有三个构建周期。clean ,default,site。
其中 default 是我们经常使用的生命周期。

clean 生命周期

只干一件事情,将编译生成的东西删除干净。

default 生命周期

默认生命周期大致由下面几个阶段组成。
resources -> compile -> testResources -> testCompile -> test -> package -> install -> deploy

介绍下我们常用的。

  • resources:拷贝 src/main/resources 下资源到 classpath 下。
  • compile:编译项目源码
  • testResources:拷贝 src/test/resources 到 测试的 test 的 classpath 下
  • test:运行单元测试
  • package:打包
  • install:安装 jar 到本地仓库
  • deploy: 发布 jar 到远程仓库或私有仓库

image.png

自定义操作到生命周期某个阶段

  1. <plugin>
  2. <groupId>org.apache.maven.plugins</groupId>
  3. <artifactId>maven-assembly-plugin</artifactId>
  4. <configuration>
  5. <descriptors>
  6. <descriptor>${basedir}/assembly/package.xml</descriptor>
  7. </descriptors>
  8. </configuration>
  9. <executions>
  10. <execution>
  11. <id>make-assembly</id>
  12. <phase>package</phase>
  13. <goals>
  14. <goal>single</goal>
  15. </goals>
  16. </execution>
  17. </executions>
  18. </plugin>

不同的生命周期一起运行。

mvn clean package
限制性 clean 生命周期,再执行 default 生命周期到 package 阶段。

私服和镜像的使用

配置镜像

mirrorOf 指定代理那个仓库 settings.xml 配置镜像

  1. <localRepository>
  2. /Users/zhangpanqin/.m2/repository
  3. </localRepository>
  4. <mirrors>
  5. <mirror>
  6. <id>aliyunmaven</id>
  7. <!-- 被镜像的中央仓库 id -->
  8. <mirrorOf>central</mirrorOf>
  9. <name>中央仓库镜像</name>
  10. <url>https://maven.aliyun.com/repository/public</url>
  11. </mirror>
  12. </mirrors>

你也可以在 pom.xml 配置私服

  1. <repositories>
  2. <repository>
  3. <id>ali_maven</id>
  4. <url>https://maven.aliyun.com/repository/central/</url>
  5. <releases>
  6. <enabled>true</enabled>
  7. </releases>
  8. <snapshots>
  9. <enabled>true</enabled>
  10. </snapshots>
  11. </repository>
  12. </repositories>

定义不同的配置环境

你也可以根据不同的配置环境,启动不同的 jdk 环境,或者根据不同的环境启动不同的镜像
settings.xml 配置。

  1. <profiles>
  2. <profile>
  3. <id>test-1</id>
  4. <activation>
  5. <activeByDefault>false</activeByDefault>
  6. </activation>
  7. <repositories>
  8. <repository>
  9. <id>public-snapshots</id>
  10. <name>public-snapshots</name>
  11. <url>http://mvn.uinnova.cn/nexus/content/groups/public</url>
  12. <releases>
  13. <enabled>true</enabled>
  14. <!--该元素指定更新发生的频率。Maven会比较本地POM和远程POM的时间戳。这里的选项是:always(一直),daily(默认,每日),interval:X(这里X是以分钟为单位的时间间隔),或者never(从不)。 -->
  15. <updatePolicy>daily</updatePolicy>
  16. <!--当Maven验证构件校验文件失败时该怎么做-ignore(忽略),fail(失败),或者warn(警告)。 -->
  17. <checksumPolicy>warn</checksumPolicy>
  18. </releases>
  19. <snapshots>
  20. <enabled>true</enabled>
  21. </snapshots>
  22. </repository>
  23. </repositories>
  24. </profile>
  25. </profiles>

也可以针对具体的项目配置

  1. <profiles>
  2. <!-- 定义配置环境 打包的环境 mvn clean package -Pdev -->
  3. <profile>
  4. <id>local</id>
  5. <properties>
  6. <profileActive>local</profileActive>
  7. </properties>
  8. <activation>
  9. <activeByDefault>false</activeByDefault>
  10. </activation>
  11. </profile>
  12. <profile>
  13. <id>dev</id>
  14. <properties>
  15. <profileActive>dev</profileActive>
  16. </properties>
  17. <activation>
  18. <activeByDefault>true</activeByDefault>
  19. </activation>
  20. </profile>
  21. <profile>
  22. <id>prod</id>
  23. <properties>
  24. <profileActive>prod</profileActive>
  25. </properties>
  26. <activation>
  27. <activeByDefault>false</activeByDefault>
  28. </activation>
  29. </profile>
  30. <profile>
  31. <id>test</id>
  32. <properties>
  33. <profileActive>test</profileActive>
  34. </properties>
  35. <activation>
  36. <activeByDefault>false</activeByDefault>
  37. </activation>
  38. </profile>
  39. </profiles>

maven-assembly-plugin 打包

pom.xml 配置

  1. <build>
  2. <finalName>flyyou</finalName>
  3. <plugins>
  4. <plugin>
  5. <groupId>org.springframework.boot</groupId>
  6. <artifactId>spring-boot-maven-plugin</artifactId>
  7. </plugin>
  8. <plugin>
  9. <groupId>org.apache.maven.plugins</groupId>
  10. <artifactId>maven-assembly-plugin</artifactId>
  11. <configuration>
  12. <descriptors>
  13. <descriptor>${basedir}/assembly/package.xml</descriptor>
  14. </descriptors>
  15. </configuration>
  16. <executions>
  17. <execution>
  18. <id>make-assembly</id>
  19. <phase>package</phase>
  20. <goals>
  21. <goal>single</goal>
  22. </goals>
  23. </execution>
  24. </executions>
  25. </plugin>
  26. </plugins>
  27. </build>

package.xml

  1. <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
  4. <!-- id 标识符,添加到生成文件名称的后缀符。如果指定 id 的话,目标文件则是 ${artifactId}-${id}.tar.gz-->
  5. <id>${project.version}-${profileActive}-bin</id>
  6. <!-- 指定打的包是否包含打包层目录(比如finalName是terminal-dispatch,当值为true,所有文件被放在包内的terminal-dispatch目录下,否则直接放在包的根目录下)-->
  7. <!-- <includeBaseDirectory>true</includeBaseDirectory>-->
  8. <!-- 打包格式有zip、tar、tar.gz (or tgz)、tar.bz2 (or tbz2)、jar、dir、war,可以同时指定多个打包格式-->
  9. <formats>
  10. <format>tar.gz</format>
  11. <format>zip</format>
  12. </formats>
  13. <fileSets>
  14. <!-- target 目录下的 jar,打包进zip文件的 lib 目录 -->
  15. <fileSet>
  16. <directory>${project.build.directory}</directory>
  17. <outputDirectory>lib</outputDirectory>
  18. <includes>
  19. <include>*.jar</include>
  20. </includes>
  21. </fileSet>
  22. <!-- 项目根目录下的 bin 目录打包进 zip bin -->
  23. <fileSet>
  24. <directory>${basedir}/bin</directory>
  25. <outputDirectory>bin</outputDirectory>
  26. <includes>
  27. <include>*.sh</include>
  28. <include>*.bat</include>
  29. </includes>
  30. </fileSet>
  31. <!-- 把项目根目录下的 doc 目录打包进 zip 中的 doc -->
  32. <fileSet>
  33. <directory>${basedir}/doc</directory>
  34. <outputDirectory>doc</outputDirectory>
  35. <includes>
  36. <include>pic/**</include>
  37. <include>*.md</include>
  38. <include>*.pdf</include>
  39. </includes>
  40. </fileSet>
  41. <!-- 把编译路径 classes 下的配置文件和日志配置文件放到 zip 中的 conf -->
  42. <fileSet>
  43. <directory>${project.build.outputDirectory}</directory>
  44. <outputDirectory>conf</outputDirectory>
  45. <includes>
  46. <include>application-${profileActive}.yml</include>
  47. <include>logback-spring.xml</include>
  48. </includes>
  49. </fileSet>
  50. </fileSets>
  51. </assembly>

image.png

配合 SpringBoot 使用

application.yml

  1. spring:
  2. application:
  3. name: flyyou-service
  4. profiles:
  5. active: @profileActive@

图形化界面切换开发环境,再也不用不停修改配置文件了作者:张攀钦
image.png
自动构建的时候使用下面命令,打包开发环境
mvn clean package -Ddev

Maven 中trueprovided之间的区别

链接:https://juejin.im/post/5edcc333e51d4578448005cc 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。