本文为我在学习群内分享时在B站直播分享时的文档,直播间地址 http://live.bilibili.com/22263819

PS:问一下,Linux下有什么好用的会议软件么? 知道的朋友烦请评论告知,感谢

00.简介

Gradle 是一种开源自动化构建工具,支持多语言环境,受 Ant、Maven 思想的影响,集二者之大成,相比 Ant 的不规范,Maven 的配置复杂、生命周期限制严重,Gradle 既规范也更灵活,可以使用DSL (领域特定语言,如Groovy 或 Kotlin)编写构建脚本,脚本更短小精悍

它的特性有:

  • 高度定制化:模块化可扩展,更灵活
  • 构建迅速:支持并行构建,自动复用之前任务构建的结果以提高效率
  • 功能强大:支持多语言环境,包含 Java、Android、C++、Groovy、Javascript 等项目的构建

Ant、Maven 有的 Gradle也有,Gradle有的它们不一定有;

Ant、Maven能干的,Gradle 都能干,而且干得更好

01.安装

Gradle 二进制包安装流程:

以 Linux 举例:

cd /opt
wget https://services.gradle.org/distributions/gradle-6.4.1-bin.zip
sudo unzip -oq gradle-6.4.1-bin.zip #解压到/opt/gradle-6.4.1
#切换root权限,设置环境变量
sudo su -
cat >> /etc/profile <<EOF
export PATH=\$PATH:/opt/gradle-6.4.1/bin
export GRADLE_USER_HOME=/opt/gradle-6.4.1 #Gradle的缓存会存在此目录下的caches中
EOF
exit
source /etc/profile #测试
hellxz@debian:~$ gradle -v ------------------------------------------------------------
Gradle 6.4.1
------------------------------------------------------------ Build time: 2020-05-15 19:43:40 UTC
Revision: 1a04183c502614b5c80e33d603074e0b4a2777c5 Kotlin: 1.3.71
Groovy: 2.5.10
Ant: Apache Ant(TM) version 1.10.7 compiled on September 1 2019
JVM: 11.0.7 (Debian 11.0.7+10-post-Debian-3deb10u1)
OS: Linux 4.19.0-9-amd64 amd64

02.Hello World

build.gradle

task hello {
println 'Hello world!'
}
gradle -q hello

-q 的作用是静默输出,使输出更加清晰

这里发生了什么? 这个构建脚本定义了一个独立的 task, 叫做 hello, 并且加入了一个 action,当你运行 gradle hello, Gradle 执行叫做 hello 的 task, 也就是执行了你所提供的 action. 这个 action 是一个包含了一些 Groovy 代码的闭包(Closure)

扩展阅读:

task块内可以定义前置、后置执行的方法(闭包)doFirstdoLast,按字面意思来理解就可以,但要注意,定义多个doLast或doFirst无法保证执行顺序

03.构建基础

projects 和 tasks

projectstasks是 Gradle 中最重要的两个概念。

任何一个 Gradle 构建都是由一个project或多个 projects 组成。每个 project 或许是一个 jar 包或者一个 web 应用,它也可以是一个由许多其他项目中产生的 jar 构成的 zip 压缩包。

每个 project 都由多个 tasks 组成每个 task 都代表了构建执行过程中的一个原子性操作。如编译,打包,生成 javadoc,发布到某个仓库等操作。

简单来说,project 相当于一个构建工程的一个模块,而 task 是其中一个模块的一个操作

调用Groovy

在 build.gradle (可以称为build script,构建配置脚本) 中可以调用 Groovy 的类库(也包含 Java 类库),下面是示例:

build.gradle

task upper {
String str = 'this is a simple test'
println "原始值:" + str
println "转大写后:" + str.toUpperCase()
}

执行命令 gradle -q upper

此示例中简单地将 this is a simple test 转成了 THIS IS A SIMPLE TEST,其中使用了 String 的 toUpperCase() 方法

Groovy 兼容 Java 语法,我们可以通过在 task 中调用 Groovy 或 Java 的方法来完成想做的操作

定义项目version/group

在 Maven 中,可以明确定义项目版本,构建时会将这个版本包含在 war 或 jar 等制品的文件名称中,推送到 Maven 私服中也需要设置 group artifactId version 信息,那么 Gradle 中如何定义呢?

Gradle 中,对应 Maven 的三个参数,将 artifactId 变成了 rootProject.name,那么只需额外定义 groupversion

build.gradle 中设置

version = "0.0.1"
group = "com.cnblogs.hellxz"

Gradle 配置中还有一个特殊的配置文件,gradle.properties,我们可以在里边配置变量供 build.gradle 读取

version=0.0.1
group=com.cnblogs.hellxz

04.Java 构建入门

生成Java项目

使用 Maven 时我们可以通过以下命令来创建一个简单的 Java 项目

mvn archetype:generate -DgroupId=xxx -DartifactId=yyy -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeCatalog=local -DinteractiveMode=false

Maven 有的 Gradle 自然也不会落下,我们可以使用 init task来初始化一个 Java 项目

$ gradle init
> Task :wrapper Select type of project to generate:
1: basic
2: application
3: library
4: Gradle plugin
Enter selection (default: basic) [1..4] 2 Select implementation language:
1: C++
2: Groovy
3: Java
4: Kotlin
5: Swift
Enter selection (default: Java) [1..5] 3 Select build script DSL:
1: Groovy
2: Kotlin
Enter selection (default: Groovy) [1..2] 1 Select test framework:
1: JUnit 4
2: TestNG
3: Spock
4: JUnit Jupiter
Enter selection (default: JUnit 4) [1..4] Project name (default: demo): Source package (default: demo): > Task :init
Get more help with your project: https://docs.gradle.org/5.4.1/userguide/tutorial_java_projects.html BUILD SUCCESSFUL
2 actionable tasks: 2 executed

生成代码的结构如下:

init task 执行的时候,优先调用 wrapper task 来生成 gradlewgradlew.bat 以及新项目所需的代码结构

带大家读文档 https://guides.gradle.org/building-java-applications/

插件:war

  • 作用:将当前项目打成war包
  • 使用:
    1. build.gradle 中添加 apply plugin: war 或在 plugins 块中添加 id: war
    2. gradle build,生成war到当前项目目录根build/libs下

生成SpringBoot2项目

带大家读文档并实践 https://guides.gradle.org/building-spring-boot-2-projects-with-gradle/

由于国内网络问题,需要配置国内源和插件源,这里把本人测试时的主要部分放出来

项目结构就是官方文档中的那样

gradle.spring.boot.project 包下的 APP.java :

/*
* This Java source file was generated by the Gradle 'init' task.
*/
package gradle.spring.boot.project; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
@SpringBootApplication
public class App extends SpringBootServletInitializer { @GetMapping("/greet")
public String getGreeting() {
return "Hello world.";
} public static void main(String[] args) {
SpringApplication.run(App.class, args);
} @Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return super.configure(builder);
}
}

build.gradle :

plugins {
id 'java'
id 'application'
id 'org.springframework.boot' version '2.0.5.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'war'
} repositories {
maven { url 'https://maven.aliyun.com/repository/public/' }
} dependencies {
implementation 'org.springframework.boot:spring-boot-dependencies:2.0.5.RELEASE'
providedCompile 'org.springframework.boot:spring-boot-starter-web'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' testImplementation 'org.springframework.boot:spring-boot-starter-test' components {
withModule('org.springframework:spring-beans') {
allVariants {
withDependencyConstraints {
// Need to patch constraints because snakeyaml is an optional dependency
it.findAll { it.name == 'snakeyaml' }.each { it.version { strictly '1.19' } }
}
}
}
}
}
application {
mainClassName = 'gradle.spring.boot.project.App'
}

settings.gradle :

pluginManagement {
resolutionStrategy {
}
repositories {
maven { url "http://maven.aliyun.com/nexus/content/groups/public" }
gradlePluginPortal()
}
} rootProject.name = 'gradle-spring-boot-project'

将SpringBoot项目打成 war 包

  • 步骤:

    • 添加 war 插件

    • 执行 gradle buildgradle bootWar (build会执行很多操作,booWar编译后只打war包)

      • 打包出可直接执行启动的war(内嵌tomcat)

      • 屏蔽tomcat依赖,继承 SpringBootServletInitializer,重写configure方法

        build.gradle

        dependencies{
        providedCompile 'org.springframework.boot:spring-boot-starter-tomcat'
        }

        App.java

        @SpringBootApplication
        public class App extends SpringBootServletInitializer{
        public static void main(String[] args){
        SpringApplication.run(App.class, args);
        }
        protected SpringApplicationBuilder configure(SpringApplicationBuilder app){
        return app.sources(App.class)
        }
        }

        gradle build 执行的 task 很多,这里放下输出

        下午4:26:33: Executing task 'build'...
        
        > Task :compileJava
        > Task :processResources NO-SOURCE
        > Task :classes
        > Task :bootWar
        > Task :bootStartScripts
        > Task :bootDistTar
        > Task :bootDistZip
        > Task :jar SKIPPED
        > Task :startScripts
        > Task :distTar
        > Task :distZip
        > Task :war SKIPPED
        > Task :assemble
        > Task :compileTestJava
        > Task :processTestResources NO-SOURCE
        > Task :testClasses
        > Task :test
        > Task :check
        > Task :build Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
        Use '--warning-mode all' to show the individual deprecation warnings.
        See https://docs.gradle.org/6.4.1/userguide/command_line_interface.html#sec:command_line_warnings BUILD SUCCESSFUL in 2s
        10 actionable tasks: 10 executed
        下午4:26:35: Task execution finished 'build'.

SpringBoot提供的tasks

  • bootWar: 编译并打成war包(需要依赖war插件才会有这个task),内部先调用classes,再调用自身,两个 task

    下午4:14:07: Executing task 'bootWar'...
    
    > Task :compileJava
    > Task :processResources NO-SOURCE
    > Task :classes
    > Task :bootWar BUILD SUCCESSFUL in 510ms
    2 actionable tasks: 2 executed
    下午4:14:08: Task execution finished 'bootWar'.
  • bootJar: 编译并打成jar包,内部先调用classes,再调用自身,两个 task

    下午4:15:31: Executing task 'bootJar'...
    
    > Task :compileJava
    > Task :processResources NO-SOURCE
    > Task :classes
    > Task :bootJar BUILD SUCCESSFUL in 488ms
    2 actionable tasks: 2 executed
    下午4:15:32: Task execution finished 'bootJar'.

05.依赖管理

导入依赖

  • compile:从仓库里下载并编译,支持依赖传递

  • api:新语法,等同compile

  • implementation:新语法,与api相比不支持传递依赖,减少循环编译优化效率

    compile/api/implementation导入的依赖都是编译期与运行期都会提供的(打进制品中)

扩展阅读:

implementation作用域

implementation的“访问隔离”只作用在编译期。

什么意思呢?如果lib C 依赖了lib A 2.0版本,lib B implementation依赖了lib A 1.0版本:

那么编译期,libC 可访问2.0版本的libA,libB可访问1.0版本的libA。

但最终打到war中的是2.0版本(通过依赖树可看到)。

在运行期,lib B 和lib C都可访问lib A的2.0版本(只能用war中的lib)

implementation的特点有哪些?

对于使用了该命令编译的依赖,对该项目有依赖的项目将无法访问到使用该命令编译的依赖中的任何程序,也就是将该依赖隐藏在内部,而不对外部公开

使用implementation有什么好处?

如果项目中有很多级联的工程依赖,比如上图中lib A B C的依赖是工程依赖。如果使用的依赖方式是compile/api,那么当lib A接口修改后重新编译时,会重新编译libA B C(即使lib C中并没有用到修改的libA的接口)。如果使用implementation依赖,因为“编译期隔离”的原因,不直接相关的lib就不会进行重新编译

如果项目中都是aar依赖,编译减少时长这个优点就没有了(因为aar已经是编译好的字节码了)。那么还有什么用呢?还是以上图为例。之前我们都是compile依赖,如果lib A已经依赖了lib B,那么在libC的build.gradle中就不用写lib A的依赖了。但这样会有问题:

我从lib C的build.gradle的依赖列表中不能完整的知道libC都需要依赖哪些lib。

假设这么一种情况,我知道项目中的依赖的libA的最高版本是2.0,那么app运行时就是使用的这个2.0版本的libA。这时候我需要打一个libC的aar。lib C如果通过compile传递依赖了libA,因此从lib C的build.gradle中不知道lib C 编译时依赖的是哪个版本的lib A。如果libC 打aar(编译)时,依赖的仍然libA 1.0,可能这个aar就有问题了。

屏蔽依赖

  • providedCompile:编译期参与编译,运行期不提供(但生成的war包中,会将这些依赖打入WEB-INF/lib-provided中)
  • providedRuntime:不参与编译但运行期需要,比如 mysql 驱动包,如果在代码里用到了此依赖则编译失败

测试期依赖

  • testCompile:测试期编译,非测试期不编译
  • testImplementation:与implementation相同,仅是测试周期的

排除依赖

  • exclude:排除指定 group module的模块

    • 引入依赖时屏蔽

      dependencies {
      compile ('org.springframework.boot:spring-boot-starter-web'){
      exclude group:'org.springframework.boot',module:'spring-boot-starter-logging'
      }
      }
    • 全局屏蔽

      configurations.all {
      exclude group:'org.springframework.boot', module:'spring-boot-starter-logging'
      }

      configurations {
      all*.exclude group:'org.springframework.boot',module:'spring-boot-starter-logging'
      }

依赖管理

  • dependencyManagement:统一多模块依赖版本

    • 可以在里边定义 dependencies 块,指定依赖版本

      dependencyManagement {
      dependencies {
      api 'mysql:mysql-connector-java:5.1.39'
      }
      }
    • 可以引入BOM,类似引入Maven的parent

      dependencyManagement {
      imports {
      mavenBom 'io.spring.platform:platform-bom:1.1.1.RELEASE'
      }
      }

06.更多

参详官方文档:

07.引文

【Gradle教程】Gradle 入门的更多相关文章

  1. 用IntelliJ IDEA创建Gradle项目简单入门

    Gradle和Maven一样,是Java用得最多的构建工具之一,在Maven之前,解决jar包引用的问题真是令人抓狂,有了Maven后日子就好过起来了,而现在又有了Gradle,Maven有的功能它都 ...

  2. Gradle 教程:第一部分,安装【翻译】

    原文地址:http://rominirani.com/2014/07/28/gradle-tutorial-part-1-installation-setup/ 在这篇教程里,我们将主要讲解如何在我们 ...

  3. Gradle 教程:第一部分,安装【翻译】(转)

    原文地址:http://rominirani.com/2014/07/28/gradle-tutorial-part-1-installation-setup/ 在这篇教程里,我们将主要讲解如何在我们 ...

  4. gradle教程 [原创](eclipse/ADT下 非插件 非Android Studio/AS)纯手打 第二篇:gradle简单实战

    一个bug 一个脚印的叫你们用gradle. 1介于网络上的很多资料都是老的 不适用与现在的新版本gradle 尤其是有些gradle方法改名了老的用不了 2介于网上都是粘贴复制并且零碎我很蛋疼啊,走 ...

  5. Gradle教程链接

    Gradle教程:https://www.yiibai.com/gradle/ https://www.cnblogs.com/wxishang1991/p/5532006.html

  6. 【Gradle】Gradle入门

    Gradle入门 配置Gradle环境 安装之前确保已经安装配置好Java环境,要求JDK6以上,并且在环境变量里配置了JAVA_HOME,查看Java版本可以在终端输入如下命令: java -ver ...

  7. 三、Gradle初级教程——Gradle除了签名打包还能配置jar包

    1.gradle概念 构建工具,Groovy,Java. 2.gradle配置jar包,和libs文件夹导入jar包的区别 到此,还是这种方法导入JAR包比较方便.每次更新JAR包,只需要修改版本号就 ...

  8. Gradle 教程:第二部分,JAVA PROJECTS【翻译】

    原文地址:http://rominirani.com/2014/07/28/gradle-tutorial-part-2-java-projects/ 在这部分的教学中,我们会学习如何使用Gradle ...

  9. Gradle:Gradle入门

    一.安装Gradle  1.首先确保你安装的JDK1.5或以上版本号.  C:\Users\chengxiang.peng.QUNARSERVERS>java -version java ver ...

随机推荐

  1. node基础知识-说说对node的理解

    一.说说你对node的理解 从定义+特点+作用来说对node的理解 定义:node是基于Chrmo v8引擎的JavaScript运行环境; 特点:具有事件驱动,非阻塞I/O模型,高并发和轻量级,单线 ...

  2. Ubuntu 拦截并监听 power button 的关机消息

    system:ubuntu 18.04 platform:rockchip 3399 board:NanoPi M4 前言 物理上的电源按键短按之后,系统直接硬关机了,导致应用程序无法保护现场,就直接 ...

  3. Windows命令行:xcopy、move、rename

    Windows命令行,xcopy复制粘贴,move剪切粘贴,rename/ren重命名.当简单事情重复做时,Windows命令行有用武之地了.批命令中,暂时用不到的行,用两个冒号注释掉. 不同路径下, ...

  4. R语言:日薪和应发工资

    生产部门普通员工为日薪,有时要知道日薪和应发工资的转换关系.做表一为日薪取整数,白天工资+晚上工资=应发工资,延长工作时间取时薪的1.5倍,应发工资保留到十位.做表二为应发工资取十的倍数,推算相应日薪 ...

  5. CF#214 C. Dima and Salad 01背包变形

    C. Dima and Salad 题意 有n种水果,第i个水果有一个美味度ai和能量值bi,现在要选择部分水果做沙拉,假如此时选择了m个水果,要保证\(\frac{\sum_{i=1}^ma_i}{ ...

  6. [hdu3484]枚举

    题意:给两个个01矩阵,有两种操作,(1)交换两列(2)反转某一行.求能否通过若干操作使两矩阵相等 思路:(把所有对B的操作放到A上来,这一定是可以做到一样的效果的)枚举B矩阵的第一列对应A矩阵的第几 ...

  7. 嫌弃Apriori算法太慢?使用FP-growth算法让你的数据挖掘快到飞起

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第20篇文章,我们来看看FP-growth算法. 这个算法挺冷门的,至少比Apriori算法冷门.很多数据挖掘的教材还会 ...

  8. Mybatis 注入全局参数

    在项目中使用mybatis作为dao层,大部分时间都需要使用到mybatis提供的动态sql功能,一般情况下所有的表都是在同一个数据库下的,进行数据操作时都是使用jdbc中默认的schema.但是如果 ...

  9. PAT 1010 Radix (25分) radix取值无限制,二分法提高效率

    题目 Given a pair of positive integers, for example, 6 and 110, can this equation 6 = 110 be true? The ...

  10. 分布式文件存储库MinIO可还行?

    在传统的单体应用架构中,一个应用程序对应一台服务器,提供单进程服务. 但是随着业务的升级,技术的更新迭代,分布式.集群架构.微服务等现已俨然成为主流. 几乎所有的项目都会与文件挂钩,例如OA系统的报表 ...