【详细步骤】Maven从无到有,理解依赖——maven使用第二弹

387 阅读5分钟

Maven

找依赖的过程

image-20201125150114273

有些公司自己会写一些工具包放到私服里,指给自己公司内部使用

maven依赖范围

classpath:编译好的class文件所在的路径

classloader:类加载器就是去对应的classpath中加载class二进制文件。

java项目

我们普通打包的jar文件,解压后最外层就是com啥啥啥包,解压后的根路径,就是class路径,classloader就从这个目录底下加载所有的c类和资源。

在我们正儿八经的工程里面。会有一个META-INF文件,有以下内容,告诉jvm执行的时候去哪个类里找main方法。

普通的java工程的类路径就是最外层目录。

image-20201125151239031 image-20201125151321590

告诉了main class 的位置,这个jar包就可以通过 java -jar执行

如果遇到了一个问题叫"没有主清单内容",就证明没有生成这个文件。

一般来说打成jar包不是为了运行(比如说一些工具类),所有没有主清单也无所谓。只是某些程序我们需要运行的时候,就需要给他指定main class

web项目

war包

image-20201125152930829

image-20201125153017847

src目录下的配置文件会和class文件一样,自动copy到应用的WEB-INF/classes目录下,所以普通jar包的类路径就是根路径,没有资源,如果有配置文件也放在src目录下,特惠同步打包在类路径下。

所以web项目的classpath是WEB-INF/classes

maven项目

maven工程会将src/main/java 和src/main/resources 文件夹下的文件全部打包在classpath中。运行时特们两个文件夹下的文件会被放在一个文件夹下。

maven项目不同的阶段引入到classpath中的依赖是不同的,例如,

  • 编译时,maven会将与编译相关的依赖引入classpath中
  • 测试时,maven会将与测试相关的饿依赖引入到classpath中
  • 运行时,maven会将与运行相关的依赖引入classpath中

而依赖范围就是用来控制依赖于这三种classpath的关系。

image-20201125201912939

双击右边的Lifecycle的名利执行各种操作。

main里面的所有东西会out在classes里,所以classpath是classes目录。

scope标签就是依赖范围的配置

该项默认配置compile,可选配置还有test、provided、runtime、system、import。

其中compile、test和provided使用较多,下面依次介绍。

有些jar包(如servlet-api)运行时其实是不需要的,因为tomcat里有,但编译时需要的,因为编译的时候没有tomcat环境

有些jar包只在测试的时候才能用,比如junit,真实运行不需要的。

有些jar运行,测试时必须要有,编译时不需要,如jdbc驱动,编译时用的都是jdk中的接口,运行时我们才使用反射注册了驱动。

编译依赖范围(compile)

该范围就是默认依赖范围,此依赖范围对于编译、测试、运行三种classpath都有效,举个简单的例子,假如项目中有fastjson的依赖,那么fastjson不管是在编译,测试,还是运行都会被用到,因此fastjson是编译依赖范围(构建默认的是编译范围,所以依赖范围是编译范围的无须显示指定)

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.68</version>
    </dependency>

测试范围依赖(test)

使用此范围的依赖,支队测试classpath有效,在编译主代码和项目运行四,都将无法使用该依赖,最典型的例子就是junit,构建在测试时才需要,所以它的依赖范围是测试,因此它的依赖范围需要显示指定为test,当然不显示指定依赖范围也不会报错,但是该依赖会被加入到编译和运行的classpath造成不必要的浪费。

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.7</version>
    <scope>test</scope>
</dependency>

已提供的依赖范围(provided)

使用该依赖范围的maven依赖,只对编译和测试的classpath有效,对运行的classpath无效,典型的例子就是servlet-api,编译和测试该项目的时候需要该依赖,但在运行是,web容器已经提供该依赖,所以运行时就不再需要此依赖,如果不显示指定该依赖的范围,并且容器依赖的版本和maven依赖的版本不一致的话,可能会引起版本冲突,造成不良影响。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

运行时依赖范围(runtime)

使用该依赖范围的maven依赖,只对测试和运行的classpath有效,对编译的classpath无效,典型的例子就是JDBC的驱动实现,项目主代码编译的时候只需要JDK提供的JDBC接口,只有在测试和运行的死后才需要实现上述接口的具体JDBC驱动,只有在运行的时候才会通过反射动态得加载connection

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connectr-java</artifactId>
    <version>5.1.25</version>
    <scope>runtime</scope>
</dependency>

依赖的传递

jar其实也是别人写的工程,特也会依赖其他的jar包,传递性让我们可以不用关心我们所依赖的jar依赖了哪些jar,只要我们添加了依赖,特惠自动将他所依赖的jar统统依赖进来。

image-20201125213352173

我们只需要依赖A.jar,其他的就会自动传递进来

依赖传递的原则

最短路径优先原则:如果A依赖于B,B依赖于C,在B和C中同时有log4j的依赖,并且这两个版本不一致,那么A会根据最短路径原则,在A中会传递过来B的log4j版本。

路径相同先声明原则:如果我们的工程同时依赖于B和A,B和C没有依赖关系,并且都有D的依赖,且版本不一致,那么会引入在pom.xml中线声明的依赖 的log4j版本。pom.xml先声明依赖B,那就用B依赖的那个D的版本。

image-20201125214945238

    <dependency>
        <groupId>com.xinzhi</groupId>
        <artifactId>B</artifactId>
        <version>1.5.3</version>
    </dependency>
    <dependency>
        <groupId>com.xinzhi</groupId>
        <artifactId>A</artifactId>
        <version>1.12.2</version>
    </dependency>

因为1.2.3先声明,所以获胜

特别注意:

不同版本的jar选一个会导致一个问题,1.3.2版本高,A.jar可能用到了高版本的一些新的方法,此时因为其他原因系统选择了低版本,就会导致A.jar报错,无法运行。那么就要想办法把低版本排除掉,一般高版本会兼容低版本。

解决上面的问题,如下

依赖的排除

把低版本的D.jar排除

<dependencies>    
    <dependency>
        <groupId>com.xinzhi</groupId>
        <artifactId>B</artifactId>
        <version>1.5.3</version>
        <exclusions>
       	  <exclusion> //排除B里面的D版本
        	  <groupId>com.xinzhi</groupId>
      		  <artifactId>D</artifactId>
       	 </exclusion>
        </exclusions>
        
    </dependency>
    <dependency>
        <groupId>com.xinzhi</groupId>
        <artifactId>A</artifactId>
        <version>1.12.2</version>
    </dependency>
</dependencies>