玩转Gradle构建工具(四)、依赖管理

718 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

前言

本系列目录

  1. Task
  2. Project、Task常用API
  3. 文件操作
  4. 依赖管理
  5. 多模块构建
  6. 插件编写
  7. SpringBoot插件源码分析
  8. 过度到Kotlin

在通过IDEA创建一个Gradle项目后,其他配置可以不需要改,但是你一定会多多少少使用第三方依赖,Gradle管理依赖比Maven更简单、简洁。

dependencies

Project提供的dependencies闭包函数用于管理依赖,通常我们在下面继续使用implementation等来引入第三方依赖,这个依赖,可以是本地模块、本地jar文件、远程仓库中jar。

 dependencies {
     configurationName dependencyNotation
 }

上述中configurationName则可以是一个implementation,当然还有其他的,比如compileOnly,dependencyNotation则表示依赖的标识符.

configurationName是可以自定义的。

implementation

如下,是引入fastjson这个库,group和name就不说了,大家都懂是什么。

dependencies {
    implementation group: 'com.alibaba', name: 'fastjson', version: '2.0.5'
}

但这样还是不行,因为我们还没告诉仓库地址,Gradle不知道从什么地方下载,所以我们还要通过repositories告诉其中一个仓库是maven中央仓库。

repositories {
     mavenCentral()
}

这个仓库并不止这一个,还可以指定一个本地仓库,比如使用mavenLocal(),表示使用maven的本地仓库。

我们知道Gradle和Maven是两种不同的构建工具,它们都有自己的本地仓库,在使用mvn install下载安装依赖时,Maven会把项目中引入的依赖下载到本地缓存起来,Gradle也是类似,他也会进行缓存,但是两种缓存的目录结构不一样,这就导致他们不通用,结果就是本地有两个用来缓存中央仓库依赖的目录,这显然很浪费空间,但我没想明白Gradle为什么要把缓存目录设计成这样,不能兼容Maven。

如果你想看他们的结构,可以去下面这个目录

Gradle:C:\Users\用户名.gradle\caches
Maven:C:\Users\用户名.m2\repository

但好在Gradle也提供了解决方案,就是使用mavenLocal(),mavenLocal()告诉Gradle先在本地Maven存储库中寻找依赖,如果不存在,则在尝试从远程获取它,但Gradle官方却建议避免添加mavenLocal(),详细可查看官网,但人家也说了,比如项目A是用Maven构建的,项目B是用Gradle构建的,开发时需要共享依赖是,需要这种方式。

repositories{ 
    mavenLocal ( ) 
    mavenCentral ( ) 
}

还有个仓库是google提供的,用于提供Android依赖,包括 Android SDK,在Java后端开发中很少见,如果使用AndroidStudio创建的Android工程,那么必定会使用google这个仓库,哦对了,Android就是使用Gradle进行构建的。

同时还可以指定一个url路径作为仓库地址,如果我们自己搭建一个服务,可以使用这种方式。

repositories {
    maven {
        url "https://repo.spring.io/release"
    }
}
dependencies {
    implementation group: 'com.gopivotal.manager', name: 'session-managers', version: '1.2.1.RELEASE'
}

如上,这个仓库是spring提供的。

注意的是,声明的顺序也决定了Gradle会按照这个顺序下载依赖,并且如果Gradle在这个仓库中找到了对应的依赖,那么这个依赖所依赖的其他依赖,也会在这同一个仓库所下载。

files

但除了中央仓库的依赖,还有一部分依赖是我们自己开发的,不在中央仓库中,那么可以通过files指定本地的jar路径。

implementation files('hibernate.jar', 'libs/spring.jar'){ include '*.jar' }

也可以把某个路径下所有jar添加到项目中。

implementation fileTree('libs'){ include '*.jar' }

project

project用于在多模块的时候使用,比如web模块要依赖system模块,可以这样写。

implementation(project(":system"))

runtimeOnly

用他来表示只有运行时候才依赖,编译时不依赖,如下,这样引入后开发时并不能使用fastjson。

dependencies {
    runtimeOnly group: 'com.alibaba', name: 'fastjson', version: '2.0.5'
}

那怎么变成运行时呢?这其实就是打包后通过java -jar运行,首先安装java这个插件,这个插件可以打包出jar文件。

plugins {
    id 'java'
}

但是对于有依赖的项目,还需要我们自己动一些手脚,如下,通过configurations.runtimeClasspath获取运行时所依赖的jar文件,然后通过zipTree解压后复制到我们项目中,这样一个完整的项目就打包好了,可以直接执行java -jar运行。

plugins {
    id 'java'
}
jar{
    manifest {
        attributes( "Main-Class": "gradle.test.App")
    }
    from{
        configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect {
            zipTree(it)
        }
    }
}

repositories {
    mavenCentral()
}
dependencies {
    runtimeOnly group: 'com.alibaba', name: 'fastjson', version: '2.0.5'
}

compileOnly

如果把它换成compileOnly,则表示只有在编译时有效,打包时不包括。

dependencies {
    compileOnly group: 'com.alibaba', name: 'fastjson', version: '2.0.5'
}

注意,implementation是两者,既在编译时存在,也在运行时存在,所以平常开发都会使用implementation,用runtimeOnly的情况可能是线上没有这个依赖,我们需要一起发布,而compileOnly则相反,我们只在本地使用他进行编译,线上环境有这个依赖了,所以我们不再发布。

其他类型

还有testCompileOnly、testRuntimeOnly、testImplementation也是类似,看名字大家都能猜到是干什么。

排除

如下,mysql驱动包还依赖protobuf-java这个包,可以使用exclude进行排除,这样在打包时,被排除的包也不会出现。

dependencies {
    implementation( group: 'mysql', name: 'mysql-connector-java', version: '8.0.29'){
        exclude group:"com.google.protobuf",module:"protobuf-java"
    }
}

查看依赖树

如果想查看某个依赖的依赖树,可以执行下面命令。

gradlew -q [模块名]:dependencies

他会列出每个配置下的依赖树,如下,这样可以直观的显示出如mysql还依赖protobuf-java这个库。

annotationProcessor - Annotation processors and their dependencies for source set 'main'.
No dependencies

apiElements - API elements for main. (n)
No dependencies
.....
runtimeClasspath - Runtime classpath of source set 'main'.
\--- mysql:mysql-connector-java:8.0.29
     \--- com.google.protobuf:protobuf-java:3.19.4

但也可以增加选项,只显示runtimeClasspath路径下的依赖。

./gradlew -q app:dependencies --configuration runtimeClasspath

上面说过,这个可以自定义,在以前的文章也演示了如何自定义,

configurations.create("myConfig")
repositories {
    mavenCentral()
}
dependencies {
//    implementation( group: 'mysql', name: 'mysql-connector-java', version: '8.0.29')
    myConfig ( group: 'mysql', name: 'mysql-connector-java', version: '8.0.29')
}

这时候可以用下面命令来显示使用myConfig所依赖的库。

./gradlew -q app:dependencies --configuration myConfig

并且可通过下面任务获取所依赖的库的所有路径。

task list{
    doLast {
        configurations.myConfig.forEach{
            println(it)
        }
    }
}