• gradle使用教程,小白一篇就够


    概述

    Gradle是新一代构建工具,从0.x版本一路走来虽然国内可寻的资料多了一些,但都是比较碎片化的知识。官方的Userguide虽然是业内良心之作,但无奈太长,且版本变化较快,又鉴于很多同学一看到英文内心便已认定无法读懂,遂打算利用业余时间攒此本《跟我学gradle》,希望通过此书可以降低学习曲线能让希望使用Gradle的同学更轻易地入门。

    简介

    Gradle是继Maven之后的新一代构建工具,它采用基于groovy的DSL语言作为脚本,相比传统构建工具通过XML来配置而言,最直观上的感受就是脚本更加的简洁、优雅。如果你之前对Maven有所了解,那么可以很轻易的转换到Gradle,它采用了同Maven一致的目录结构,可以与Maven一样使用Maven中央仓库以及各类仓库的资源,并且Gradle默认也内置了脚本转换命令可以方便的将POM转换为gradle.build。

    Gradle的优势

    依赖管理: 即将你项目中的jar包管理起来,你可以使用Maven或者Ivy的远程仓库、或者本地文件系统等

    编译打包: 可以通过脚本实现花样打包,包括修改文件、添加抑或排除某些类或资源、采用指定JDK版本构建、打包后自动上传等等

    多项目支持: Gradle对多项目有着良好的支持,比如一个很具有代表性的实践就是spring framework
    多语言支持:无论是java、groovy、scala、c++都有良好的支持
    跨平台支持:gradle是基于jvm的,只要有jvm你就可以让gradle运行
    灵活的的脚本:你可以使用groovy灵活的编写任务完成你想要做的任何事情

    约定优于配置
    约定优于配置(convention over configuration),简单而言就是遵循一定的固定规则从而可以避免额外的配置。虽然这一定程度上降低了灵活性,但却能减少重复的额外配置,同时也可以帮助开发人员遵守一定的规则。当然,约定并不是强制性约束,Gradle提供了各种灵活的途径可以让你更改默认的配置。

    标准结构
    Gradle遵循COC(convention over configuration约定优于配置)的理念,默认情况下提供了与maven相同的项目结构配置
    大体结构如下

    project root
    src/main/java(测试)
    src/main/resources
    src/test/java(测试源码目录)
    src/test/resources(测试资源目录)
    src/main/webapp(web工程)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    非标准结构配置

    在一些老项目上,可能目录结构并不是标准结构,然而一般开发人员又不好进行结构调整.此时可以通过配置sourceSet来指定目录结构

    sourceSets {
        main {
            java {
                srcDir 'src/java'
            }
            resources {
                srcDir 'src/resources'
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    或者采用如下写法也是可以的

    sourceSets {
        main.java.srcDirs = ['src/java']
        main.resources.srcDirs = ['src/resources']
    }
    
    • 1
    • 2
    • 3
    • 4

    在android中

    android {
        sourceSets {
            main {
                manifest.srcFile 'AndroidManifest.xml'
                java.srcDirs = ['src']
                resources.srcDirs = ['src']
                aidl.srcDirs = ['src']
                renderscript.srcDirs = ['src']
                res.srcDirs = ['res']
                assets.srcDirs = ['assets']
            }
    
            androidTest.setRoot('tests')
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    当然如果你的资源目录与源码目录相同这样就比较…了,但你仍然可以按照如下方式搭配include和exclude进行指定

    sourceSets {
      main {
        java {
          //your java source paths and exclusions go here...
        }
    
        resources {
          srcDir 'main/resources'
          include '**/*.properties'
          include '**/*.png'
    
    
          srcDir 'src'
          include '**/Messages*.properties'
          exclude '**/*.java'
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    一个简单的Gralde脚本,或许包含如下内容,其中标明可选的都是可以删掉的部分

    插件引入:声明你所需的插件
    属性定义(可选):定义扩展属性
    局部变量(可选):定义局部变量
    属性修改(可选):指定project自带属性
    仓库定义:指明要从哪个仓库下载jar包
    依赖声明:声明项目中需要哪些依赖
    自定义任务(可选):自定义一些任务

    //定义扩展属性(给脚本用的脚本)
    buildScript {
        repositories {
             mavenCentral()
        }
    }
    
    //应用插件,这里引入了Gradle的Java插件,此插件提供了Java构建和测试所需的一切。
    apply plugin: 'java'
    //定义扩展属性(可选)
    ext {
        foo="foo"
    }
    //定义局部变量(可选)
    def bar="bar"
    
    //修改项目属性(可选)
    group 'pkaq'
    version '1.0-SNAPSHOT'
    
    //定义仓库,当然gradle也可以使用各maven库 ivy库 私服 本地文件等,后续章节会详细介绍(可选)
    repositories {
        jcenter()
    }
    
    //定义依赖,这里采用了g:a:v简写方式,加号代表了最新版本(可选)
    dependencies {
        compile "cn.pkaq:ptj.tiger:+"
    }
    
    //自定义任务(可选)
    task printFoobar {
        println "${foo}__${bar}"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    buildscript 配置该 Project 的构建脚本的 classpath,在 Andorid Studio 中的 root project 中可以看到
    apply(options: Map)我们通过该方法使用插件或者是其他脚本,options里主要选项有:

    • from: 使用其他脚本,值可以为 Project.uri(Object) 支持的路径

    • plugin:使用其他插件,值可以为插件id或者是插件的具体实现类

    apply plugin: 'com.android.application'
    //使用插件,MyPluginImpl 就是一个Plugin接口的实现类
    apply plugin: MyPluginImpl
    
    //引用其他gradle脚本,push.gradle就是另外一个gradle脚本文件
    apply from: './push.gradle'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    扩展:
    Gradle脚本是基于groovy的DSL,这里对上述脚本与Gradle api的关系稍作解释,希望可以帮助你更好的理解groovy与gradle dsl之间的关系

    //project 的buildScript方法  实际返回的是一个ScriptHandler对象
    buildScript {
        repositories {
             mavenCentral()
        }
    }
    //调用apply方法 参数是一个 map,调用时参数省略了括号
    apply plugin: 'java'
    //定义扩展属性(可选)
    ext {
        foo="foo"
    }
    //定义局部变量(可选)
    def bar="bar"
    
    //修改项目属性(可选)
    group 'pkaq'
    version '1.0-SNAPSHOT'
    
    //project 的repositories 方法  实际返回的是一个RepositoryHandler对象
    repositories {
        jcenter()
    }
    
    //project 的dependencies 方法  实际返回的是一个DependencyHandler对象
    dependencies {
        compile "cn.pkaq:ptj.tiger:+"
    }
    
    //调用Task task(String name, Closure configureClosure)方法
    task printFoobar {
        println "${foo}__${bar}"
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    什么是依赖管理?

    通常而言,依赖管理包括两部分,对依赖的管理以及发布物的管理;依赖是指构建项目所需的构件(jar包等)。例如,对于一个应用了spring普通的java web项目而言,spring相关jar包即项目所需的依赖。发布物,则是指项目产出的需要上传的项目产物。

    采用变量统一控制版本号

    dependencies {
        def bootVersion = "1.3.5.RELEASE"
        compile     "org.springframework.boot:spring-boot-starter-web:${bootVersion}",  
                    "org.springframework.boot:spring-boot-starter-data-jpa:${bootVersion}",
                    "org.springframework.boot:spring-boot-starter-tomcat:${bootVersion}"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    自动获取最新版本依赖

    如果你想某个库每次构建时都检查是否有新版本,那么可以采用+来让Gradle在每次构建时都检查并应用最新版本的依赖。当然也可以采用1.x,2.x的方式来获取某个大版本下的最新版本。

    dependencies {
        compile     "org.springframework.boot:spring-boot-starter-web:+"
    }
    
    
    • 1
    • 2
    • 3
    • 4

    依赖的坐标

    仓库中构件(jar包)的坐标是由configurationName
    "group:name:version:classifier@extension"组成的字符串构成,如同Maven中的GAV坐标,Gradle可借由此来定位你想搜寻的jar包。

    在gradle中可以通过以下方式来声明依赖:

    testCompile group: 'junit', name: 'junit', version: '4.0'
    
    • 1

    在gradle中可以通过以下方式来声明依赖:

    testCompile group: 'junit', name: 'junit', version: '4.0'
    
    • 1

    在这里插入图片描述

    这是由于Gradle依赖配置支持多种书写方式,采用map或者字符串。

    // 采用map描述依赖
    testCompile group: 'junit', name: 'junit', version: '4.0'
    // 采用字符串方式描述依赖
    testCompile 'junit:junit:4.0'
    
    • 1
    • 2
    • 3
    • 4

    显然采用字符串的方式更加简单直观,当然借助groovy语言强大的GString还可以对版本号进行抽离。如下面的示例,这里需要注意的是如果要用GString的话,依赖描述的字符串要用""双引号包起来才会生效。

    def ver = "4.0"
    testCompile "junit:junit:${ver}"
    
    • 1
    • 2

    依赖的范围

    上面的例子中采用的testComplie是声明依赖的作用范围,关于各种作用范围的功效可见下表。

    tip:这里需要注意的是,provided范围内的传递依赖也不会被打包

    在这里插入图片描述

    依赖的分类

    在这里插入图片描述

    外部依赖

    可以通过如下方式声明外部依赖,Gradle支持通过map方式或者g🅰️v的简写方式传入依赖描述,这些声明依赖会去配置的repository查找。

    dependencies {
     // 采用map方式传入单个
      compile group: 'commons-lang', name: 'commons-lang', version: '2.6'
     // 采用map方式传入多个
      compile(
          [group: 'org.springframework', name: 'spring-core', version: '2.5'],
          [group: 'org.springframework', name: 'spring-aop', version: '2.5']
      )
      // 采用简写方式声明
      compile 'org.projectlombok:lombok:1.16.10' 
      // 采用简写方式传入多个 
      compile 'org.springframework:spring-core:2.5',
              'org.springframework:spring-aop:2.5'
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    项目依赖

    此类依赖多见于多模块项目,书写方式如下,其中:是基于跟项目的相对路径描述符。

     compile project(':project-foo')
    
    • 1

    文件依赖

    依赖存在于本地文件系统中,举个栗子,如oracle的OJDBC驱动,中央仓库中没有又没有自建私服此时需要放到项目lib下进行手工加载那么便可采用此种方式,可以通过FileCollection接口及其子接口提供的方法加载这些依赖(支持文件通配符)

    dependencies {
       // 指定多个依赖
       compile files('hibernate.jar', 'libs/spring.jar')
    
       // 读取lib文件夹下的全部文件作为项目依赖
       compile fileTree('libs')
    
       // 根据指定基准目录\包含\排除条件加载依赖
       compile fileTree(dir:'libs',include:'spring*.jar',exclude:'hibernate*.jar')
     }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    内置依赖

    跟随Gradle发行包或者基于Gradle API的一些依赖,通常在插件开发时使用,当前提供了如下三种

     dependencies {
       // 加载Gradle自带的groovy作为依赖
       compile localGroovy()
    
       // 使用Gradle API作为依赖
       compile gradleApi()
    
       /使用 Gradle test-kit API 作为依赖
       testCompile gradleTestKit()
     }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    子模块依赖

    简单来说就是声明依赖的依赖或者依赖的传递依赖,一般情况下如果依赖的库并未用构建工具构建(尤其是一些上古时代的老库),那么Gradle是无法透过源文件去查找该库的传递性依赖的,通常而言,一个模块采用XML(POM文 件)来描述库的元数据和它的传递性依赖。Gradle可以借由此方式提供相同的能力,当然这种方式也会可以改写原有的传递性依赖。这里让druid连接池依赖了ptj.tiger的一个库。

    dependencies {
        // 让ptj.tiger作为druid的传递性依赖
        compile module("com.alibaba:druid:1.0.26") {
                dependency("cn.pkaq:ptj.tiger:+")
        }
    
        runtime module("org.codehaus.groovy:groovy:2.4.7") {
            // 停用groovy依赖的commons-cli库的依赖传递
            dependency("commons-cli:commons-cli:1.0") {
                transitive = false
            }
            // 让groovy依赖的ant模块的依赖ant-launcher停用传递性依赖并依赖ant-junit..........
            module(group: 'org.apache.ant', name: 'ant', version: '1.9.6') {
                dependencies "org.apache.ant:ant-launcher:1.9.6@jar",
                             "org.apache.ant:ant-junit:1.9.6"
            }
        }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    什么是传递依赖?

    在Maven仓库中,构件通过POM(一种XML文件)来描述相关信息以及传递性依赖。Gradle 可以通过分析 该文件获取获取所以依赖以及依赖的依赖和依赖的依赖的依赖,为了更加直观的表述,可以通过下面的输出 结果了解。

    在这里插入图片描述

    可以看到,我们的项目依赖了com.android.support-v4包,然而com.android.support-v4包却依赖了一众support的全家桶,借助Gradle的传递性依赖特性,你无需再你的脚本中把这些依赖都声明一遍,你只需要简单的一行,Gradle便会帮你将传递性依赖一起下载下来。

    传递依赖特性可以轻松地通过transitive参数进行开启或关闭,上面的示例中如果要忽略com.android.support-v4的传递性依赖可以采用指定 transitive = false 的方式来关闭依赖传递特性,也可以采用添加@jar的方式忽略该依赖的所有传递性依赖。

     compile('com.android.support:support-v4:23.1.1'){
            transitive = false
     }
    
    
    • 1
    • 2
    • 3
    • 4
     compile 'com.android.support:support-v4:23.1.1'@jar
    
    
    • 1
    • 2

    当然,你也可以全局性的关闭依赖的传递特性。

     configurations.all {
       transitive = false
    }
    
    • 1
    • 2
    • 3

    排除依赖

    有些时候你可能需要排除一些传递性依赖中的某个模块,此时便不能靠单纯的关闭依赖传递特性来解决了。这时exclude就该登场了,如果说@jar彻底的解决了传递问题,那么exclude则是部分解决了传递问题。然而实际上exclude肯能还会用的频率更更频繁一些,比如下面几种情况。

    可以通过configuration配置或者在依赖声明时添加exclude的方式来排除指定的引用。

    exclude可以接收group和module两个参数,这两个参数可以单独使用也可以搭配使用,具体理解如下:

    compile('com.github.nanchen2251:CompressHelper:1.0.5'){
            //com.android.support:appcompat-v7:23.1.1
            exclude group: 'com.android.support'//排除组织依赖
            exclude module: 'appcompat-v7'//排除模块依赖
     }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    强制使用版本

    当然,有时候你可能仅仅是需要强制使用某个统一的依赖版本,而不是排除他们,那么此时force就该登场了。指定force = true属性可以冲突时优先使用该版本进行解决

    compile('com.github.nanchen2251:CompressHelper:1.0.5'){
            force = true
     }
    
    
    • 1
    • 2
    • 3
    • 4

    全局配置强制使用某个版本的依赖来解决依赖冲突中出现的依赖

    configurations.all {
       resolutionStrategy {
           force 'com.github.nanchen2251:CompressHelper:1.0.5'
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    另一个例子:

    //解决冲突 同一版本
    configurations.all {
        resolutionStrategy.eachDependency { DependencyResolveDetails details ->
            def requested = details.requested
            if (requested.group == 'com.android.support') {
                if (requested.name.startsWith("support-")||
                        requested.name.startsWith("animated")||
                        requested.name.startsWith("cardview")||
                        requested.name.startsWith("design")||
                        requested.name.startsWith("gridlayout")||
                        requested.name.startsWith("recyclerview")||
                        requested.name.startsWith("transition")||
                        requested.name.startsWith("appcompat")) {
                    details.useVersion '25.0.0'
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    使用动态版本

    如果你想让你的工程始终采用最新依赖,那么Gradle提供了一种方式可以始终保证采用依赖的最新版本而无需每次手工检查修改版本。

    使用加号+,可以让Gradle在每次执行构建时检查远程仓库是否存在该依赖的新版本,如果存在新版本则下载选用最新版本。当然也可以指定依赖某个大版本下的最新子版本,1.+表示始终采用该依赖最新的1.x版本的最新依赖。

      compile 'com.android.support:support-v4:+'//下载最新
      compile 'com.android.support:support-v4:23+'//基于23这个版本最新
    
    
    • 1
    • 2
    • 3

    虽然这是看上去十分风骚的一种用法,但这无疑会降低你系统构建的速度同时提高构建失败的风险。因为Gradle不得不每次检查远程仓库是否存在最新版本,同时新版本也可能带来无法预知的兼容性问题。

    一个综合案例

    compile('com.github.nanchen2251:CompressHelper:1.0.5') {
       // 冲突时优先使用该版本
       force = true
    
       // 依据构建名称排除
       exclude module: 'CompressHelper' 
       // 依据组织名称排除
       exclude group: 'com.github.nanchen2251' 
       // 依据组织名称+构件名称排除
       exclude group: 'com.github.nanchen2251', module: 'CompressHelper' 
    
       // 为本依赖关闭依赖传递特性
       transitive = false
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    使用config.gradle文件统一管理项目依赖

    1. 在项目的根目录下创建config.gradle文件

    在这里插入图片描述

    1. 编辑 config.gradle,定义项目依赖

    在app的build.gradle中,我们通常需要配置两个部分

    Android 目录下的项目的版本/包名/编译版本等信息 dependencies 目录下的安卓Support库和我们自己引用的第三方库
    所以通常我们在config.gradle文件也将依赖分成两个部分 android/dependencies

    ext {
    
        android = [
                compileSdkVersion      : 28,
                buildToolsVersion      : "28.0.0",
                applicationId          : "com.will.weiyue",
                minSdkVersion          : 19,
                targetSdkVersion       : 28,
                versionCode            : 1,
                versionName            : "1.0"
        ]
        //因为support库都是同一个版本,单独拎出来,方便修改
        dependVersion = [
                support: "28.0.0-alpha3"
        ]
    
        dependencies = [
                // android-support
                "support-v4"            : "com.android.support:support-v4:${dependVersion.support}",
                "appcompat-v7"          : "com.android.support:appcompat-v7:${dependVersion.support}",
                "design"                : "com.android.support:design:${dependVersion.support}",
                "recyclerview"          : "com.android.support:recyclerview-v7:${dependVersion.support}",
                "cardview"              : "com.android.support:cardview-v7:${dependVersion.support}",
        ]
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    1. 在 项目的 build.gradle文件中引用config.gradle文件
    // 在项目build.gradle文件的最外层添加引用
    apply from: "config.gradle"
    
    
    • 1
    • 2
    • 3
    1. 修改app的build.gradle文件中的项目引用
    // 将android 和 dependencies下的引用都指向 config.gradle
    // rootProject.ext.android/dependencies  config.gradle文件的路径
    android {
        compileSdkVersion rootProject.ext.android.compileSdkVersion
        defaultConfig {
            applicationId rootProject.ext.android.applicationId
            minSdkVersion rootProject.ext.android.minSdkVersion
            targetSdkVersion rootProject.ext.android.targetSdkVersion
            versionCode rootProject.ext.android.versionCode
            versionName rootProject.ext.android.versionName
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation rootProject.ext.dependencies["appcompat-v7"]
        implementation rootProject.ext.dependencies["constraint-layout"]
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    更新依赖

    在执行build、compile等任务时会解析项目配置的依赖并按照配置的仓库去搜寻下载这些依赖。默认情况下,Gradle会依照Gradle缓存->你配置的仓库的顺序依次搜寻这些依赖,并且一旦找到就会停止搜索。如果想要忽略本地缓存每次都进行远程检索可以通过在执行命令时添加–refresh-dependencies参数来强制刷新依赖。

    gradle build --refresh-dependencies
    
    • 1

    当远程仓库上传了相同版本依赖时,有时需要为缓存指定一个时效去检查远程仓库的依赖笨版本,Gradle提供了cacheChangingModulesFor(int, java.util.concurrent.TimeUnit) ,cacheDynamicVersionsFor(int, java.util.concurrent.TimeUnit)两个方法来设置缓存的时效

    configurations.all {
        //每隔24小时检查远程依赖是否存在更新
        resolutionStrategy.cacheChangingModulesFor 24, 'hours'
        //每隔10分钟..
        //resolutionStrategy.cacheChangingModulesFor 10, 'minutes'
        // 采用动态版本声明的依赖缓存10分钟
        resolutionStrategy.cacheDynamicVersionsFor 10*60, 'seconds'
    }
    
    dependencies {
        // 添加changing: true
        compile group: "group", name: "module", version: "1.1-SNAPSHOT", changing: true
        //简写方式
        //compile('group:module:1.1-SNAPSHOT') { changing = true }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    缓存管理

    缓存位置管理

    Gradle在按照配置的仓库去搜寻下载依赖时,下载的依赖默认会缓存到USER_HOME/.gradle/caches目录下,当然也可以手工修改这个位置。
      具体可以参考如下三种方式:

    • 通过添加系统变量 GRADLE_USER_HOME
    • 设置虚拟机参数 org.gradle.user.home 属性
    • 通过命令行-g或者 --gradle-user-home 参数设置

    离线模式(总是采用缓存内容)

    Gradle提供了一种离线模式,可以让你构建时总是采用缓存的内容而无需去联网检查,如果你并未采用动态版本特性且可以确保项目中依赖的版本都已经缓存到了本地,这无疑是提高构建速度的一个好选择。开启离线模式只需要在执行命令时候添加–offline参数即可。当然,采用这种模式的也是有代价的,如果缓存中搜寻不到所需依赖会导致构建失败。

    gradle build --offline
    
    • 1

    依赖-构件的上传与发布

    借助maven-publish插件可以轻松地将jar包发布到仓库中。这个过程没啥幺蛾子直接上代码吧。了解更多配置可以查看 Maven plugin插件章节

    apply plugin: 'maven-publish'
    apply plugin: 'java'
    
    // 打包源文件
    task sourceJar(type: Jar) {
        from sourceSets.main.allSource
        classifier = 'sources'
    }
    
    task javadocJar(type: Jar, dependsOn: javadoc) {
        classifier = 'javadoc'
        from javadoc.destinationDir
    }
    
    publishing {
         // 目标仓库
        repositories {
            maven {
               url "xxx"
            }
        }   
    
        publications {          
            mavenJava(MavenPublication) {
                // 设置gav属性
                groupId 'org.pkaq'
                artifactId 'tiger'
                version '1.1'
    
                from components.java
                artifact sourceJar
    
                 // 设置pom相关信息
                pom.withXml {
                    Node root = asNode()              
                    root.appendNode('description', 'bazinga!')
                }
            }
        }
    
    }
    //生成一个元的pom文件
    model {
        tasks.generatePomFileForMavenJavaPublication {
            destination = file("$buildDir/generated-pom.xml")
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    检查依赖

    在引用的依赖或传递性依赖存在版本冲突时,Gradle采用的策略是优先选取最新的依赖版本解决版本冲突问题。。如何知道哪些依赖传递了哪些子依赖,哪些传递的依赖又被Gradle进行了隐性升级呢。采用下面的命令可以查看各个范围的依赖树。

    gradle  dependencies > dep.log
    
    
    • 1
    • 2

    输出结果:

    dependencies
    
    ------------------------------------------------------------
    Root project
    ------------------------------------------------------------
    
    archives - Configuration for archive artifacts.
    No dependencies
    
    compile - Dependencies for source set 'main'.
    +--- org.springframework.boot:spring-boot-starter-web:1.4.2.RELEASE
    |    +--- org.springframework.boot:spring-boot-starter:1.4.2.RELEASE
    |    |    +--- org.springframework.boot:spring-boot:1.4.2.RELEASE
    |    |    |    +--- org.springframework:spring-core:4.3.4.RELEASE
    |    |    |    |    \--- commons-logging:commons-logging:1.2
    |    |    |    \--- org.springframework:spring-context:4.3.4.RELEASE
    |    |    |         +--- org.springframework:spring-aop:4.3.4.RELEASE
    |    |    |         |    +--- org.springframework:spring-beans:4.3.4.RELEASE
    |    |    |         |    |    \--- org.springframework:spring-core:4.3.4.RELEASE (*)
    |    |    |         |    \--- org.springframework:spring-core:4.3.4.RELEASE (*)
    |    |    |         +--- org.springframework:spring-beans:4.3.4.RELEASE (*)
    |    |    |         +--- org.springframework:spring-core:4.3.4.RELEASE (*)
    |    |    |         \--- org.springframework:spring-expression:4.3.4.RELEASE
    ....
    ....
    省略的
    ....
    ....
    \--- org.apache.tomcat.embed:tomcat-embed-jasper:8.5.4
         +--- org.apache.tomcat.embed:tomcat-embed-core:8.5.4 -> 8.5.6
         +--- org.apache.tomcat.embed:tomcat-embed-el:8.5.4 -> 8.5.6
         \--- org.eclipse.jdt.core.compiler:ecj:4.5.1
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    后面dep.log文件名可以随意,然而,你一定在想为什么有些带了()有的带了->有的什么都没有呢,这是什么鬼。前面已经说过,当发生版本冲突时Gradle会采用最新版本解决。仔细观察带了()的依赖你会发现这些依赖被不同的库重复依赖了若干次,这里(*)的意思即是表示该依赖被忽略掉了。而->则表示其它的定级依赖的传递依赖中存在更高版本的依赖,该版本将会使用->后面的版本来替代。

    反向查找

    如果你想知道某个依赖到底被哪个库引用过,可以采用下面的命令进行反向查找

    gradle dependencyInsight  --dependency tomcat-embed-core > reverse.log 
    
    
    • 1
    • 2

    示例如下:

    :dependencyInsight
    org.apache.tomcat.embed:tomcat-embed-core:8.5.6 (conflict resolution)
    +--- org.apache.tomcat.embed:tomcat-embed-websocket:8.5.6
    |    \--- org.springframework.boot:spring-boot-starter-tomcat:1.4.2.RELEASE
    |         \--- org.springframework.boot:spring-boot-starter-web:1.4.2.RELEASE
    |              \--- compile
    \--- org.springframework.boot:spring-boot-starter-tomcat:1.4.2.RELEASE (*)
    
    org.apache.tomcat.embed:tomcat-embed-core:8.5.4 -> 8.5.6
    \--- org.apache.tomcat.embed:tomcat-embed-jasper:8.5.4
         \--- compile
    
    (*) - dependencies omitted (listed previously)
    
    BUILD SUCCESSFUL
    
    Total time: 6.936 secs
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    上面的报告中可以看到8.5.6这个版本后面标注了(conflict resolution) 说明了该版本是用于解决冲突选用的版本。

    冲突即停

    Gradle默认采用自动升级版本的方式解决依赖冲突,有时这种隐式升级可能会带来一些不必要的麻烦,此时我们可以通过更改这种默认行为来让Gradle发现版本冲突时立即停止构建并抛出错误信息。
    更改脚本:

    configurations.all {
      resolutionStrategy {
        failOnVersionConflict()
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    执行gradle build的输出结果:

    :compileJava FAILED
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Could not resolve all dependencies for configuration ':compileClasspath'.
    > A conflict was found between the following modules:
       - org.apache.tomcat.embed:tomcat-embed-core:8.5.4
       - org.apache.tomcat.embed:tomcat-embed-core:8.5.6
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    可以看到在执行gradle build时由于tomcat-embed-core存在版本冲突导致了构建失败,并提示了冲突的两个版本。

    依赖报告

    Gradle官方提供了一个名叫project-report插件可以让依赖查看更加简单方便,要用此插件只需要在脚本中添加apply plugin: 'project-report’即可。该插件提供的任务可以参考下面的表格,所有输出结果将被放在build/report下。

    在这里插入图片描述

    使用插件检查更新

    使用三方插件进行检查,可以使依赖固定在一个相对新的版本,这里需要注意的是,plugins需要放置在脚本的顶部,更多关于plugins的内容可以查看官方文档

    plugins {
       id "name.remal.check-dependency-updates" version "1.0.6" 
    }
    
    
    • 1
    • 2
    • 3
    • 4

    应用此插件后,可以执行gradle checkDependencyUpdates 或 gradle cDU 检查依赖最新版本 : }

    > Task :web:checkDependencyUpdates
    New dependency version: com.alibaba:druid: 1.0.29 -> 1.1.7
    
    • 1
    • 2
  • 相关阅读:
    amlogic-android9.0-hdmi调试
    高速无源链路阻抗匹配套路
    C树和森林的研究学习随记【一】
    Python的偏函数
    Pandas数据分析26——pandas对象可视化.plot()用法和参数
    No qualifying bean of type ‘...‘ available错误解决
    ThreadLocal使用及原理
    WRF4.2安装过程全记录
    Revit插件“土建模块”的生成圈梁功能使用
    使用 ErrorStack 在出现报错 ORA-14402 时产生的日志量
  • 原文地址:https://blog.csdn.net/hai411741962/article/details/133068125