查了一天资料,终于搞明白了Maven的依赖范围

633 阅读4分钟

最近看到Maven的依赖范围,之前的工作中一直在使用,但是其实并不是完全了解,查阅了很多资料,发现很多资料上介绍的都很模糊,没有具体的案例,因此写了两个module测试不同范围的依赖有什么影响。

1. Maven依赖范围说明

项目依赖范围可以如下表:

依赖范围(Scope)对于编译classpath有效对于测试calsspath有效对于运行时classpath有效说明
compileYYY默认依赖范围,例子Spring-core
test-Y-JUnit
providedYY-Servlet-api
runtime-YYJDBC驱动实现
systemYY-本地的,Maven仓库之外的类库文件
import---通常用在dependencyManagement中

三种classpath可以分别理解为:

编译classpath: 代码的引用,也就是在src包下是否可以引用该代码

测试classpath: 测试引用,是都可以在单元测试用使用

运行classpath: 代码运行时可以引用,其他场景不能引用

2. 详细演示

2.1 compile说明

2.1.1 环境说明

假设有两个module,分别为module-amodule-b,module-b依赖module-a,

module-a的pom依赖为

<groupId>com.marco</groupId>
    <artifactId>module-a</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

module-a中创建一个User类

public class User {
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

module-bpom文件为

		<groupId>com.marco</groupId>
    <artifactId>module-b</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>com.marco</groupId>
            <artifactId>module-a</artifactId>
            <version>1.0.0</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

module-b中的通过new方式创建对象演示代码

public class ModuleATest {
    public static void main(String[] args) {
        User user = new User();
        user.setId(1L);
        user.setName("小林同学");

        System.out.println(user);
    }
}

module-b中的通过反射方式创建对象演示代码

public class ModuleAReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> userClass = Class.forName("com.marco.obj.User");
        Constructor<?> constructor = userClass.getConstructor();
        Object obj =  constructor.newInstance();
        System.out.println(obj);
    }
}
2.1.2 运行结果

通过new方式创建对象运行结果正常

通过反射方式创建User对象运行结果正常

image-20201031171016225

2.2 test说明

2.2.1 test环境配置

module-bmodule-a的依赖改成test

<groupId>com.marco</groupId>
    <artifactId>module-b</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>com.marco</groupId>
            <artifactId>module-a</artifactId>
            <version>1.0.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
2.2.2 运行结果

main方法中已经找不到了User类了,说明编译classPath已经找不到这个类

image-20201031164527832

test通过反射运行结果提示找不到类

image-20201031170915626

test中的方法未报错

image-20201031164721612

运行单元测试结果正常

image-20201031164802890

通过上面测试代码印证了上表中的依赖范围

2.3 provided说明

2.3.1 provided环境说明

修改module-b的pom依赖scope为provided

<groupId>com.marco</groupId>
    <artifactId>module-b</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>com.marco</groupId>
            <artifactId>module-a</artifactId>
            <version>1.0.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
2.3.2 运行结果

代码在idea是正常的,可以找到类

image-20201031165203282

运行结果报错,提示找不到类,

image-20201031165324374

这里我们把通过反射来创建User

image-20201031171122033

单元测试结果是正常的,就不贴了

2.4 runtime说明

2.4.1 runtime环境说明

module-b的POM文件中依赖scope改成runtime

<groupId>com.marco</groupId>
    <artifactId>module-b</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>com.marco</groupId>
            <artifactId>module-a</artifactId>
            <version>1.0.0</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
2.4.2 运行结果

正常new对象提示找不到该类

image-20201031171801292

通过反射得到的结果是正确的

image-20201031172612824

测试结果也是正确的

image-20201031172709237

2.6 import详细说明

import中的依赖范围不会对三种classpath产生实际的影响,一般只是用在dependencyManagement

3.总结

Maven的依赖范围最复杂的就是providedruntime

provided常用于编译和测试项目的时候有效,在运行时无效的场景。例如servlet-api,编译和测试的时候需要该依赖,但项目运行的时候,容易会提供,因此不需要重复引入。

runtime对于测试和运行的时候有效,但编译代码时无效。例如JDBC驱动实现,项目主代码中只需要提供JDBC接口,在测试运行时才需要实现具体的JDBC实现类。

其他依赖范围都相对简单,就不过多赘述了。 写了一天,各位大佬走过路过帮忙给个赞吧~~~