依赖管理
在项目中如果我们需要引入一个依赖,一般直接在官网https://mvnrepository.com查找,然后将其添加到maven的pom.xml
文件中的<dependencies/>
即可,如下:
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
其中<scope>
标签用于指定其生效范围,用来控制依赖的编译,其主要的是依赖关系如下:
- compile:默认编译依赖范围。 被依赖项目在编译,测试,运行都参与,依赖的jar包会在项目打包时包含进去,随着项目直接发布。
- provided: 依赖的jar包在运行期无效,在项目打包时也不会包含进去,在运行时由服务器提供。如servlet-api
- runtime: 运行时使用,依赖的jar无需参与项目的编辑,如jdbc驱动
- test: 依赖的jar包仅仅参与测试相关的工作,如测试代码的编译、执行
- system: 不建议使用,不依赖maven仓库解析,需要提供依赖的显示路径,对项目的移植来说极不方便
另外上图中的<version>
标签用于来制定依赖jar包的版本号,一般来说所有非-SNAPSHOT
结尾的版本号,都是稳定的版本RELEASE
一般来说我们在引入依赖的jar包时,会指定其版本号,这样Maven在解析过程中首先尝试直接从本地仓库寻找jar包,若本地仓库不存在,则遍历所有的远程仓库,找到相应的jar包后进行下载使用。
当然如果执行的版本号不是稳定的版本号,而是以-SNAPSHOT
结尾的快照版本,那么无论本地仓库中是否存在对应得jar包,Maven都会从远程仓库中进行下载更新本地仓库。
最后其实还有两种不推荐的使用方式,就是<version>RELEASE</version>
每次都会使用发布的最新稳定版本,以及<version>LATEST</version
每次都会使用最新的版本(包含快照版本)
在项目中引入依赖jar包时,我们经常会碰到一个问题,就是依赖冲突,通常的原因一般是同一个jar包由于maven传递依赖等原因被引进了多个不同的版本而导致。
比如上图中project项目会使用哪个fastjson包呢,这里主要依据最短最先原则:
- 路径最短原则:inventory 和 user 里的引用路径较短
- 同路径长度下,谁先声明谁优先:看 inventory 和 user 依赖在pom中声明位置
- 使用
clusions
排除,比如可以声明不要 inventory 和 user 不要fastjson的依赖
至于exclusions
的用法,也非常的简单,比如:
<dependency>
<groupId>com.rockvine</groupId>
<artifactId>user</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</exclusion>
</exclusions>
</dependency>
最后再来介绍一下pom.xml
文件中<dependencyManagement>
和<properties>
的用法,一般在父子项目中使用,其作用是提供了一种管理依赖版本号的方式,在父项目的pom.xml
文件中声明所依赖的jar包的版本号等信息
那么所有子项目再次引入此依赖jar包时则无需显式的列出版本号。Maven会沿着父子层级向上查找对应得版本号。
这里我们需要注意<dependencies>
与<dependencyManagement>
的区别:
- 对于
<dependencies>
来说,即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(全部继承) - 而
<dependencyManagement>
只是声明依赖,并不实现引入,因此子项目需要显式的引入需要用的依赖,如果不在子项目中引入依赖,是不会从父项目中继承下来的。
只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version
和scope
都读取自父项目的pom.xml
文件;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本
另外其实对于<dependencyManagement>
还有一个极少的用法,用来实现多继承,比如我们一个项目继承了一个父项目,但是父项目不是一个SpringBoot项目,而我们子项目希望是一个SpringBoot项目,而Maven只能单继承,即一个项目只能使用<parent>
标签定一个父级项目,所以这里就可以使用<dependencyManagement>
。
需要注意的是,这里我们还需要设置其scope=import
,即表示继承此项目为父项目
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
环境激活
在实际项目中开发中,通常会用开发、测试、预发、线上等多个环境,配置文件往往也不同。所以打包时需要对配置文件做出选择,Maven就为我们提供了profiles机制。
如上图项目结构中,我们在resources
目录下新建了dev
及prod
文件夹,其中我们分别针对不同的环境进行相关的配置,那么我们在打包的时候该如何处理呢?
首先我们需要在pom.xml
文件中,进行定义profiles
,如下:
上述定义的意思是,当mvn命令执行时,我们可以通过-P dev
或者-P prod
方式传入我们的意图,即dev/prod
的选择,会导致properties里的定义变量package.environment
值的不同。
maven打包过程中会默认会将resources文件夹下全部复制,这里我们可以先将resources下的dev和prod文件夹排除,然后根据上述变量package.environment
的值来复制指定的配置信息
<build>
<finalName>cache</finalName>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>dev/*</exclude>
<exclude>prod/*</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>compile</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<overwrite>true</overwrite>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<resources>
<resource>
<directory>src/main/resources/${package.environment}</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
上述其实就是利用了Maven的生命周期及插件开发中介绍的生命周期default
的process-resources
,其相对应的maven-resources-plugin
插件可以复制指定的主资源文件至主输出目录,其中${project.build.outputDirectory}
是maven的内置变量,无需设置
然后我们执行Mavne的打包命令了,按照上述的设置其默认的是dev配置,如果希望指定配置则使用-P
,如下:
上述仅仅配置了其默认激活的配置,其中还可以做更多的选项,如部分可使用配置如下:
另外还可以直接在环境中定义属性值,如下: