maven依赖范围
所谓依赖范围,指的是 依赖的jar包在maven项目生命周期里 作用的范围。
之前我们讲过,构建的gav坐标包括groupId
、artifactId
和version
,其实还有一个scope
。如果没有明示scope
,则默认是compile
。这里的compile
就是依赖范围的一种,表示项目在编译、运行、测试、打包的这些生命周期里都依赖这个jar包,这个jar包在这些阶段都在起作用。
scope
有以下5个值,分别是
compile
,表示编译、运行、测试和打包阶段都依赖这个jar包。
比如,某个项目对spring-core
的依赖。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.9</version>
<scope>compile</scope>
</dependency>
因为scope
的默认值是compile
,所以<scope>compile</scope>
可以忽略不写,如下,
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.9</version>
</dependency>
provided
,表示编译、运行阶段会依赖这个jar包。
比如,容器相关的依赖,servlet-api
,如下所示。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
来看个具体的例子。
首先,在IDEA中使用模板创建一个web项目。
然后,修改pom.xml
,引入对servlet-api
的依赖,同时添加tomcat插件,插件用于后续的命令行运行。添加的内容如下所示。
<!-- 引入依赖servlet -->
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- 引入tomcat插件 -->
<build>
<finalName>oct02</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
可以看到依赖servlet的scope
值是provided
。
最后,我们使用命令行tomcat7:run
运行下这个项目。
以上步骤很完美,没毛病。
现在,把servlet的scope
值更改为compile
,或者干脆把scope
这行删掉(因为scope
的默认就是compile
嘛),如下所示。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>compile</scope>
</dependency>
改好后,我们再来运行下项目。
这下问题来了:HTTP Status 500 - java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/jasper/servlet/JasperLoader) previously initiated loading for a different type with name “javax/servlet/http/HttpServletRequest”。
violation,“冲突”的意思。依赖servlet-api和tomcat自带的servlet之间发生了冲突,所以打包时就不应该包含servlet-api,即scope
值就不应该是compile
。
system
,表示编译、运行阶段会依赖这个jar包。
作用范围和provided
相同。区别是,system
必须配合systemPath
一起使用,systemPath
用来指定依赖的本地路径。如下所示,其中,${project.basedir}
表示项目的根目录。
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<scope>system</scope>
<version>4.5.25</version>
<systemPath>${project.basedir}/lib/aliyun-java-sdk-core-4.5.25.jar</systemPath>
</dependency>
实际项目中,system
这个范围很少使用。
runtime
,表示只在运行阶段才会依赖这个jar包。但在打包的时候也会将该jar包包含进来。
jdbc驱动就是这么一个使用场景,编译时不需要jdbc驱动,运行时则需要具体的第三方实现的jar包(如mysql-connector-java)。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
<scope>runtime</scope>
</dependency>
test
,表示只在测试阶段才会依赖这个jar包。
这个比较好理解,常见的就是junit,如下所示,
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
maven父子项目的依赖传递
构建一个父子项目,就能理解项目里的依赖传递关系了。
首先,新建一个基本的java项目,记作oct02_parent
。
然后,修改项目的pom.xml
,修改后的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>org.example</groupId>
<artifactId>oct02_parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 父项目的打包方式-->
<packaging>pom</packaging>
<name>oct02_parent</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<junit.version>4.11</junit.version>
<spring.version>5.3.9</spring.version>
<log4j.version>1.2.17</log4j.version>
</properties>
<!-- 父项目的基本依赖-->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
</dependencies>
<!-- 父项目中统一管理依赖(依赖容器,在子项目中使用时才会引入)-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
具体修改主要有以下3点内容,分别是,
第一点,如果没有明示,<packaging/>
的默认值是jar
。但父项目的打包方式必须为pom
,所以<packaging>pom</packaging>
。
第二点,<dependencies/>
中添加的依赖,会直接引入,而<dependencyManagement>
中添加的依赖,只有子项目使用时,才会引入。这也是为什么当前父项目的External Libraries
中只能看到mysql-connector-java(jdk1.8是本地依赖,mysql-connector-mysql依赖protobuf-java)。
第三点,在<properties/>
中定义变量spring.version
、log4j.version
和junit.version
的值,并使用${spring.version}
、${log4j.version}
、${junit.version}
来确定所用依赖的最终版本。
这样做,方便实现依赖版本的统一管理。比如,一旦涉及到spring整体升级或回退,只需要修改一处就行。
父项目建立好了,在oct02_parent
下创建一个子项目:一个基本的java项目oct02_child
。
修改子项目oct02_child
的pom.xml
,建立oct02_parent
和oct02_child
之间的父子关系。
<!--继承关系:继承一个项目-->
<parent>
<groupId>org.example</groupId>
<artifactId>oct02_parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<!-- 继承关系中,子项目会自动继承父项目的groupId-->
<!-- <groupId>org.example</groupId>-->
<artifactId>oct02_child</artifactId>
<version>1.0-SNAPSHOT</version>
使用<parent/>
为子项目oct02_child
指定父项目,注意哈,<relativePath/>
是父项目oct02_parent
的pom文件所在路径(相对路径)。
继承关系建立起来后,子项目便会自动继承父项目的groupId。
父项目oct02_parent
的pom文件中<dependencies/>
中添加的依赖,子项目oct02_child
会全部自动继承,所以,可以在子项目的External Libraries
中看到这些继承下来jar包:mysql-connector-java,如下图所示。
父项目oct02_parent
的pom文件中<dependencyManagement/>
中添加的依赖,只有子项目oct02_child
使用时才会引入到项目中。比如,在子项目中使用以下依赖。
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
</dependencies>
关于父子项目的依赖传递,用下面一个图做一个小结。
父子项目的优缺点是比较明显的。
优点:可以合理有效地复用依赖jar包;子项目互相独立,更加便于敏捷开发和独立管理。
缺点:项目之间的系统集成性能比较差。
maven项目聚合统一管理
聚合项目不仅实现了依赖jar包的复用,同时也较好地解决了父子项目的缺点,项目的聚合关系使得项目之间的整体性提高,便于系统集成和维护。
构建一个聚合项目,就能理解项目是怎么进行聚合统一管理。
在这里,笔者不使用maven模板,所以在IDEA中提前设置好maven的home path、settings file和local repositories,如下图所示。
首先,新建一个项目oct03_aggregation
。
然后,修改pom.xml
,顶级项目的<packaging/>
的值也必须是pom
,如下所示。
<groupId>org.example</groupId>
<artifactId>oct03_aggregation</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
New >Module,新建子模块oct03_module01
。
可以看到,子模块oct03_module01
自动与顶级模块oct03_aggregation
建立了继承关系。
<!--子模块oct03_module01的pom.xml的部分内容 -->
<parent>
<artifactId>oct03_aggregation</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>oct03_module01</artifactId>
顶级模块oct03_aggregation
也自动聚合了子模块oct03_module01
。
<!--顶级模块oct03_aggregation的pom.xml的部分内容 -->
<modules>
<module>oct03_module01</module>
</modules>
maven项目常用插件
maven提供了很多插件,可以到maven官网(https://maven.apache.org/)看看。
比如有生命周期插件,clean
、compiler
、deploy
、install
、resources
等,也有常用的操作插件,比如jar
、dependency
、Apache Tomcat
等等。
之前有介绍如何使用tomcat插件,现在来讲讲如何使用dependency插件。
首先,在官网上查看下dependency插件的用法。
然后,使用maven模板新建一个聚合项目。
顶级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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>oct03_aggregation</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>oct03_module01</module>
</modules>
<packaging>pom</packaging>
<name>oct03_aggregation</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<spring.version>5.3.9</spring.version>
<junit.version>4.11</junit.version>
<log4j.version>1.2.17</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
子模块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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example</groupId>
<artifactId>oct03_aggregation</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>oct03_module01</artifactId>
<name>oct03_module01</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
提示:如果子模块自动生成的pom.xml
中没有<parent/>
,可以自己手动加上。
再然后,在子模块的pom.xml
中添加dependency插件,如下所示。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.2.0</version>
</plugin>
最后添加maven命令:dependency:tree
便可查看子模块的依赖树。
以上只是为了演示如何使用maven插件 。
其实,要查看依赖树结构,使用Diagrams这种图形化展示,更直观。