工具篇 | Gradle入门与使用指南

介绍

1.1 什么是Gradle?

Gradle是一个开源构建自动化工具,专为大型项目设计。它基于DSL(领域特定语言)编写,该语言是用Groovy编写的,使得构建脚本更加简洁和强大。Gradle不仅可以构建Java应用程序,还支持多种语言和技术,例如C++、Python、Android等。
更多信息和详细文档可以在Gradle官方网站上找到。

1.2 为什么选择Gradle?

与其他流行的构建工具(如Maven和Ant)相比,Gradle提供了以下优势:

  • 性能:Gradle使用它的守护程序和增量构建技术来提高构建速度。你可以在1查看Gradle与其他工具的性能对比图。
    在这里插入图片描述

  • 灵活性:Gradle的DSL使你可以编写高度定制化的构建脚本。

  • 可扩展性:Gradle可以通过插件机制轻松扩展,有着丰富的插件生态系统。

  • Android官方支持:对于Android开发,Google官方推荐使用Gradle作为构建工具。


安装和设置

2.1 前提条件

在安装Gradle之前,你需要确保满足以下前提条件:

  • 一个有效的Java Development Kit (JDK)安装。Gradle 7.0及以上版本需要JDK版本为8到16。
  • JAVA_HOME 环境变量已正确设置,指向JDK的安装目录。

2.2 下载和安装Gradle

  1. 直接下载:你可以从Gradle官方下载页面下载最新版本的Gradle分发包。选择合适的分发包,通常我们使用二进制分发包。

  2. 使用包管理器:对于某些操作系统,如macOS,你可以使用Homebrew包管理器来安装:

    brew install gradle
    

    对于Linux用户,可以使用SDKMAN:

    sdk install gradle
    
  3. 解压下载的文件到一个合适的安装位置。

  4. 将解压后的路径添加到你的操作系统的PATH变量中,以便从任何位置运行Gradle命令。

2.3 验证安装

要验证你的Gradle安装是否成功,可以在命令行或终端中运行以下命令:

gradle -v

会显示Gradle的版本、Groovy的版本以及JVM版本等详细信息,如下图所示:
在这里插入图片描述


Gradle基础概念

3.1 项目和任务

在Gradle中,构建是由项目任务组成的。

  • 项目:代表你正在构建的东西,可以是一个库、应用程序或者是一个更大的单元,如多模块项目。一个构建可以有一个或多个项目。
  • 任务:表示一个原子的构建操作,例如编译类或创建JAR文件。

3.2 构建脚本

Gradle使用构建脚本来配置和控制构建过程。这些脚本默认使用GroovyKotlin DSL编写,并具有特定的文件名,如build.gradlebuild.gradle.kts
构建脚本定义了项目和任务以及它们之间的关系。

3.3 依赖管理

Gradle不仅仅是一个构建工具,它还有一个强大的依赖管理系统,允许你声明你的项目依赖的外部库,并自动下载和管理它们。

3.4 插件

插件扩展了Gradle的功能,使得常见的构建任务和配置变得简单。例如,Java插件为Java项目添加了常见的任务,如编译和打包。
使用插件通常是通过在构建脚本中声明它们来完成的。例如:

plugins {id 'java'
}

3.5 生命周期

Gradle任务有一个生命周期,包括三个阶段:

  1. 初始化:在此阶段,Gradle决定要处理哪些项目。
  2. 配置:在此阶段,Gradle构建所有的项目的任务对象。
  3. 执行:在此阶段,Gradle运行实际的任务。

创建和运行你的第一个Gradle项目

4.1 初始化项目

你可以使用Gradle的命令行界面创建一个新的项目。例如,要创建一个新的Java应用程序,可以运行以下命令:

gradle init --type java-application

指定一些版本号,就会在当前目录下生成一个新的Java项目。
在这里插入图片描述

4.2 项目结构

上面的命令执行完毕后,会在目录下创建这样的一个结构:
在这里插入图片描述

4.3 编写代码

它默认会在app/src/main/java目录中添加一个简单的App类。

public class App {public String getGreeting() {return "Hello World!";}public static void main(String[] args) {System.out.println(new App().getGreeting());}
}

4.4 构建项目

在项目的根目录中,运行以下命令来构建项目:

gradle build

这会编译Java类、运行任何测试(如果有的话)并创建一个JAR文件。
在这里插入图片描述

4.5 运行应用

如果你已经使用--type java-application来初始化项目,你可以使用以下命令来运行你的应用:

gradle run

你应该会看到Hello World!的输出。
在这里插入图片描述


Gradle构建脚本基础

5.1 build.gradle文件的作用

build.gradle是Gradle构建的核心。它是一个用Groovy或Kotlin DSL编写的脚本,用于定义项目的构建逻辑。它描述了如何编译和打包代码,如何运行测试,以及如何发布成果物。

5.2 任务(Tasks)

任务是构建的原子操作。每个任务都代表了构建过程中的一个步骤。例如,编译源代码、运行单元测试、生成文档等。

tasks.register('myTask') {doLast {println 'This is a custom task.'}
}

上面的代码定义了一个名为myTask的任务,当其被执行时,会在控制台上打印出消息。我们把这段话复制到刚刚的build.gradle下,然后执行就会打印这句话:
在这里插入图片描述

5.3 依赖(Dependencies)

任务之间可能存在依赖关系。这意味着一个任务可能依赖于其他一个或多个任务的成功执行。

tasks.register('taskA') {doLast {println 'Task A is executed.'}
}tasks.register('taskB') {dependsOn 'taskA'doLast {println 'Task B is executed.'}
}

在上面的例子中,taskB依赖于taskA。当你执行taskB时,首先会执行taskA。如图所示:
在这里插入图片描述

5.4 插件(Plugins)

插件是一种强大的扩展Gradle功能的方式。它们可以提供额外的构建任务,增强现有任务,甚至改变Gradle的核心行为。下面列举了一些常用的插件和它们的作用。

plugins {id 'java' // Java插件,为Java项目提供编译、测试和打包的任务id 'application' // Application插件,可以创建可运行的应用程序,提供了‘run’任务来运行应用id 'war' // War插件,用于构建Java Web应用程序,提供了生成WAR文件的任务
}

Java插件

java插件是最基础的插件之一,提供了用于Java项目的核心任务,如compileJava来编译Java源代码和test来运行测试。

Application插件

application插件扩展了java插件,提供了创建可执行Java应用程序所需的功能。最重要的是,它添加了run任务,允许你直接从Gradle运行你的应用。

War插件

war插件是为Java Web应用程序设计的,用于生成WAR文件,这是Java EE和Servlet容器通常使用的部署格式。

其他插件

Gradle拥有丰富的插件生态系统,包括但不限于Android开发、Spring Boot集成、Docker构建等。你可以浏览Gradle Plugin Portal来查找更多可用的插件。
每个插件都有其独特的配置和用法,因此在使用新插件时,请务必查阅其官方文档,以了解如何正确配置和使用它们。
不同的插件解决了不同的问题,但它们都遵循着同样的设计原则和配置方式,一旦你熟悉了几个常用插件的用法,就能快速学会使用新的插件。


常用的Gradle任务

在Gradle中,每一个构建动作都是通过执行一个或多个任务来完成的。当我们引入插件时,这些插件通常会为我们预定义一些任务。以下,我们将深入探讨一些常用的Gradle任务。

6.1 清理

任务名称: clean
这是一个非常常用的任务。当执行此任务时,Gradle会删除构建目录,确保下一次构建是从干净的状态开始的。
使用命令:

gradle clean

6.2 构建

任务名称: build
此任务是Java插件提供的。当执行此任务时,Gradle会执行完整的构建周期,包括编译、测试等。
使用命令:

gradle build

6.3 测试

任务名称: test
该任务也是Java插件提供的。它负责运行项目的单元测试。
使用命令:

gradle test

6.4 运行

任务名称: run
为了使用此任务,我们需要引入application插件,并设置主类。

plugins {id 'application'
}
mainClassName = 'com.example.Main'

然后,可以使用以下命令来运行应用:

gradle run

依赖管理

在大多数软件项目中,我们通常依赖于第三方库来完成某些功能。Gradle提供了一个强大的依赖管理系统,使得声明、解析和使用这些第三方库变得轻而易举。

7.1 声明仓库

要使用外部依赖,首先需要告诉Gradle从哪里获取它们。最常用的仓库是Maven Central和JCenter。
例如,要添加Maven Central仓库,你可以这样写:

repositories {mavenCentral()
}

如果你想使用JCenter仓库:

repositories {jcenter()
}

7.2 声明和使用依赖

一旦设置了仓库,就可以开始添加依赖了。
例如,要在Java项目中使用Google的Gson库,可以如下添加:

dependencies {implementation 'com.google.code.gson:gson:2.8.6'
}

其中,implementation表示这是一个主要的运行时依赖。

7.3 依赖冲突解决

有时,当你的项目依赖于多个库,并且这些库依赖于相同库的不同版本时,就会发生冲突。Gradle有强大的冲突解决策略,通常会选择最新的版本。
但如果你需要更精确的控制,可以这样做:

configurations.all {resolutionStrategy {force 'com.google.code.gson:gson:2.8.5'}
}

这将确保项目中使用的Gson库版本为2.8.5,即使其他依赖可能请求了一个不同的版本。


使用插件

Gradle插件为构建和管理项目提供了额外的功能。从Java到Android,再到Spring Boot,几乎所有的现代框架和平台都有自己的Gradle插件来简化相关任务。

8.1 常见的插件

  • Java 插件: 这是最常用的插件之一,它为Java项目提供了编译、测试和打包的功能。

    plugins {id 'java'
    }
    
  • Application 插件: 如果你正在构建一个应用程序,这个插件可以帮助你打包并运行它。

    plugins {id 'application'
    }
    
  • War 插件: 为Web应用程序提供支持,使你能够构建WAR文件。

    plugins {id 'war'
    }
    

8.2 如何应用插件

你已经看到了如何应用一个插件,那么我们将更深入地了解它。插件可以从Gradle插件门户、Maven仓库或本地文件应用。

  • 从Gradle插件门户应用(目前主流做法,简洁):

    plugins {id 'org.springframework.boot' version '2.5.4'
    }
    
  • 从Maven仓库应用:

    buildscript {repositories {mavenCentral()}dependencies {classpath("org.springframework.boot:spring-boot-gradle-plugin:2.5.4")}
    }apply plugin: 'org.springframework.boot'
    
  • 从本地文件应用:

    apply from: 'other.gradle'
    

8.3 插件的配置

大多数插件都提供了一组可配置的属性来定制它们的行为。例如,application插件允许你指定应用的主类:

application {mainClassName = 'com.example.Main'
}

建议查看官方文档或插件的文档来了解所有可用的配置选项。


多项目构建

大型应用程序和库通常不仅仅是一个孤立的项目。它们可能由多个子项目组成,每个子项目都负责特定的功能。Gradle支持多项目构建,允许你在一个构建中管理和编译多个项目。

9.1 设置子项目

在你的主项目目录下,创建一个settings.gradle文件(如果尚未存在),并声明子项目:

include 'subproject1', 'subproject2'

此处的subproject1subproject2是子项目的目录名。

9.2 配置和执行跨项目的任务

每个子项目都可以有自己的build.gradle文件,其中定义了该子项目的构建逻辑。但在根项目中,你可以定义影响所有子项目的构建逻辑:

subprojects {apply plugin: 'java'repositories {mavenCentral()}dependencies {testImplementation 'junit:junit:4.12'}
}

上面的代码片段将Java插件、Maven Central仓库和JUnit依赖添加到所有子项目中。
要在所有子项目上执行任务,只需在根目录下运行该任务。例如,运行gradle build将构建所有子项目。
如果只想在一个特定的子项目上执行任务,可以这样:

gradle :subproject1:build

多项目构建是Gradle的强大特性之一,尤其是对于大型的代码库。通过合适地组织和配置,你可以确保整个代码库的一致性和可维护性。


自定义任务和扩展

10.1 编写自己的任务

在创建自定义任务时,推荐使用tasks.register方法来注册新的任务。这是一个懒加载的方法,意味着任务只有在真正需要时才会创建。

abstract class HelloTask extends DefaultTask {@TaskActiondef sayHello() {println 'Hello, Gradle!'}
}tasks.register('hello', HelloTask)

此处使用abstract关键字是因为Gradle会为任务生成具体的实现。
运行gradle hello将输出Hello, Gradle!
在这里插入图片描述

10.2 使用Gradle的API

对于现有的任务,我们通常使用tasks.withType来对某种特定类型的所有任务进行配置:

tasks.withType(HelloTask).configureEach {// 这里可以为每个HelloTask类型的任务进行配置
}

10.3 扩展的概念

Gradle扩展依然是为项目定义自定义属性的推荐方式。但在新的API中,推荐使用extensions.create的方式:

extensions.create('myExtension', MyExtension)abstract class MyExtension {String customProperty = 'default value'
}

通过自定义任务和扩展,你可以使Gradle构建过程更加灵活和强大。它们提供了一种机制,使你可以适应项目的特定需求,同时还能保持构建脚本的可读性和组织性。


构建缓存和增量构建

构建优化对于大型项目和频繁的构建操作非常关键。Gradle 提供了两个强大的特性来加速构建:构建缓存和增量构建。

11.1 为什么需要缓存?

每次运行构建时,都有很多任务是重复的,尤其是在没有对代码或资源做任何修改的情况下。构建缓存的作用是存储已经执行过的任务的输出,以便在将来的构建中重用,从而避免不必要的工作。

11.2 构建缓存的使用和配置

默认情况下,Gradle 使用本地构建缓存。你可以通过以下方式在项目的 settings.gradlesettings.gradle.kts 文件中启用或禁用它:

buildCache {local {enabled = true}
}

此外,Gradle 也支持远程构建缓存,这在团队开发中非常有用,因为它允许团队成员之间共享构建的输出。

11.3 增量构建

增量构建是指只对自上次构建以来发生变化的部分进行构建。为了使任务支持增量构建,你需要确保:

  • 使用@Input@Output注解来声明任务的输入和输出。
  • 使用@Incremental注解在TaskAction方法上。
    Gradle 会自动跟踪这些输入和输出之间的变化,并在可能的情况下只执行所需的工作。

11.4 示例:增量构建

假设我们有一个任务,该任务将源文件从一个目录复制到另一个目录,并将所有文件的扩展名更改为 .txt。我们可以这样做:

11.4.1添加一个自定义任务

build.gradle 文件的顶部,添加以下内容:

import org.gradle.work.InputChanges
abstract class IncrementalCopyTask extends DefaultTask {@InputDirectoryabstract DirectoryProperty getSourceDir()@OutputDirectoryabstract DirectoryProperty getTargetDir()@TaskActionvoid executeIncremental(InputChanges inputChanges) {inputChanges.getFileChanges(getSourceDir()).each { change ->switch (change.changeType.name()) {case "ADDED":case "MODIFIED":def targetFile = new File(getTargetDir().asFile, change.file.name + '.txt')change.file.copyTo(targetFile)breakcase "REMOVED":new File(getTargetDir().asFile, change.file.name + '.txt').delete()break}}}
}

build.gradle 的底部,注册这个任务:

tasks.register('incrementalCopy', IncrementalCopyTask) {sourceDir = file('src/main/resources')targetDir = file("$buildDir/output")
}

这样,我们就为 src/main/resources 目录中的文件定义了一个增量复制任务,输出目录是 build/output

11.4.2运行任务

为了测试这个任务,你可以首先在 src/main/resources 中创建一些文件,然后运行:

$ gradle incrementalCopy

你会看到这些文件被复制到 build/output 目录,并且它们的扩展名都被更改为 .txt

如果你再次运行该任务,不做任何改动,Gradle 会检测到没有任何变化,因此不会执行任何复制操作,这就是增量构建的威力。试试在 src/main/resources 中添加、修改或删除文件,然后再次运行任务。你会看到只有发生变化的文件才会被处理。这就是一个简单的增量构建示例。你可以在此基础上进一步扩展或修改来满足你的实际需求。


Gradle Wrapper的使用

12.1 什么是Gradle Wrapper?

Gradle Wrapper是一个工具,允许你在没有预先安装Gradle的情况下执行构建。这样做的好处是可以确保每个开发者和持续集成工具都使用相同版本的Gradle,避免了“在我的机器上可以运行”这样的问题。Wrapper由一个小的gradlew(Unix系统)或gradlew.bat(Windows系统)脚本和一些库文件组成。

12.2 为什么要使用Gradle Wrapper?

  1. 版本一致性:确保每个开发者和CI环境都使用相同的Gradle版本。
  2. 简化构建过程:开发者无需手动安装特定版本的Gradle。
  3. 灵活性:项目可以很容易地切换到新的Gradle版本,只需修改Wrapper配置即可。

12.3 如何设置Gradle Wrapper?

大部分通过gradle init初始化的新项目默认就包含了Wrapper。但如果你的项目还没有Wrapper,可以很容易地添加:

$ gradle wrapper --gradle-version=7.2

这会为你的项目生成Wrapper脚本和相关配置。

12.4 如何使用Gradle Wrapper?

一旦你的项目配置了Wrapper,你应该使用Wrapper脚本来运行所有Gradle任务,而不是直接使用gradle命令。例如:
在Unix或macOS上:

$ ./gradlew <task>

在Windows上:

> gradlew.bat <task>

如果你看到有人在项目的README或构建指南中推荐使用gradlew而不是gradle,这就是为什么。

12.5更新Gradle Wrapper的版本

随着Gradle的发展,你可能想要更新项目中的Gradle版本。使用Wrapper,这变得很容易。例如,要更新到Gradle 7.3,你可以运行:

$ ./gradlew wrapper --gradle-version=7.3

这会更新Wrapper使用的Gradle版本,并下载必要的文件。

总结

Gradle Wrapper是Gradle的一个强大特性,它确保了构建的一致性和简化了开发和CI环境的配置。为你的项目使用Wrapper是一个最佳实践,无论项目大小都推荐这样做。


参考文献

  1. 云原生—Gradle和Maven性能对比及技术选型 - 稀土掘金
  2. Gradle | Releases - 官方文档
  3. Gradle | Plugins - 官方文档
  4. Gradle 比 Maven 好为什么用的人少? - 知乎
  5. Gradle 快速入门
  6. Gradle 详细手册(从入门到入土) - 稀土掘金
  7. 如何使用Gradle管理多模块Java项目 - 知乎
  8. Android—Gradle教程(一) - 稀土掘金
  9. GradleUserGuide - GitHub
  10. Github Actions - GitHub

  1. https://juejin.cn/post/7209178782657675319 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/138215.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Redis】深入探索 Redis 的哨兵(Sentinel)机制原理,基于 Docker 模拟搭建 Redis 主从结构和哨兵分布式架构

文章目录 一、对 Redis Sentinel 的认识1.1 什么是 Redis Sentinel1.2 为什么要使用 Redis Sentinel1.2.1 主从复制问题1.2.2 人工恢复主节点故障 二、Redis Sentinel 原理剖析2.1 Redis Sentinel 架构2.2 Raft 算法和领袖节点2.3 哨兵节点2.4 故障检测2.5 故障切换2.6 监控和通…

利用大模型知识图谱技术,告别繁重文案,实现非结构化数据高效管理

我&#xff0c;作为一名产品经理&#xff0c;对文案工作可以说是又爱又恨&#xff0c;爱的是文档作为嘴替&#xff0c;可以事事展开揉碎讲清道明&#xff1b;恨的是只有一个脑子一双手&#xff0c;想一边澄清需求一边推广宣传一边发布版本一边申报认证实在是分身乏术&#xff0…

基于矩阵分解算法的智能Steam游戏AI推荐系统——深度学习算法应用(含python、ipynb工程源码)+数据集(三)

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据预处理2. 模型构建1&#xff09;定义模型结构2&#xff09;优化损失函数 3. 模型训练及保存1&#xff09;模型训练2&#xff09;模型保存 4. 模型应用1&#xff09;制作页面2&#xff09;模型导入及调用3&am…

zabbix监控多实例redis

Zabbix监控多实例Redis 软件名称软件版本Zabbix Server6.0.17Zabbix Agent5.4.1Redis6.2.10 Zabbix客户端配置 编辑自动发现脚本 vim /usr/local/zabbix/scripts/redis_discovery.sh #!/bin/bash #Fucation:redis low-level discovery #Script_name redis_discovery.sh red…

【操作系统】实验一 Linux初步

文章目录 Linux初步一、实验目的二、实验内容 Linux初步 一、实验目的 通过proc文件系统观察整个Linux内核和系统的一些重要特征&#xff0c;并编写一个程序&#xff0c;使用proc文件系统获得以及修改系统的各种配置参数。 本实验需要学生具有Linux的基本操作技能&#xff0c…

Rust常见编程概念

变量和可变性 rust使用let声明变量&#xff0c;变量默认是不可改变的。通过在let后面加上mut&#xff0c;可以声明可变变量。可以在变量名后加:和类型名&#xff0c;来显式声明变量类型&#xff0c;例如&#xff1a; let a:u32 1; 常量 常量使用const声明&#xff0c;变量名…

【Tricks】关于如何防止edge浏览器偷取chrome浏览器的账号

《关于如何防止edge浏览器偷取chrome浏览器的账号》 前段时间edge自动更新了&#xff0c;我并没有太在意界面的问题。但是由于我使用同一个网站平台时&#xff0c;例如b站&#xff0c;甚至是邮箱&#xff0c;edge的账号和chrome的账号会自动同步&#xff0c;这就导致我很难短时…

Centos7部署gitlab

建议服务器配置不低于2C8G 1、安装必要的依赖 sudo yum install -y curl policycoreutils-python openssh-server perl2、配置极狐GitLab 软件源镜像 curl -fsSL https://packages.gitlab.cn/repository/raw/scripts/setup.sh | /bin/bash sudo yum install gitlab-jh -y3、…

安防视频/视频汇聚平台EasyCVR使用onvif探测添加设备通道详细步骤来啦!

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…

uniapp打包安卓后在安卓屏上实现开机自启动

实现开机自启动(使用插件) 打开插件地址安卓开机自启动 Fvv-AutoStart - DCloud 插件市场 使用方法 选择你要开启自启动的项目 在项目的manifest.json中app-plus下写入以下代码 注意需要替换 android_package_name 为自己的,不然无法进行安卓apk打包 "nativePlugins&q…

【计算机网络】IP协议第一讲(协议格式介绍)

IP协议 1.协议头格式1.1 概念介绍1.2补充说明1.2.1 8位生存时间---TTL1.2.2 16位首部检验和 首先明确一个概念&#xff1a;TCP/IP协议是配合使用的&#xff0c;TCP负责可靠传输策略&#xff0c;IP则是负责传输&#xff0c;TCP协议是位于传输层提供的是策略解决可靠性问题&#…

pytest一些常见的插件

Pytest拥有丰富的插件架构&#xff0c;超过800个以上的外部插件和活跃的社区&#xff0c;在PyPI项目中以“ pytest- *”为标识。 本篇将列举github标星超过两百的一些插件进行实战演示。 插件库地址&#xff1a;http://plugincompat.herokuapp.com/ 1、pytest-html&#xff1…

【操作系统】聊聊什么是CPU上下文切换

对于linux来说&#xff0c;本身就是一个多任务运行的操作系统&#xff0c;运行远大于CPU核心数的程序&#xff0c;从用户视角来看是并发执行&#xff0c;而在CPU视角看其实是将不同的CPU时间片进行分割&#xff0c;每个程序执行一下&#xff0c;就切换到别的程序执行。那么这个…

EasyExcel看完肯定行

EasyExcel看完肯定行 1.随便创建一个Excel表格 2.引入依赖 <dependencies><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version></dependency><!-- 方便操作…

【Redis】Redis 的学习教程(十一)之使用 Redis 实现分布式锁

1. 分布式锁概念 在多线程环境下&#xff0c;为了保证数据的线程安全&#xff0c;锁保证同一时刻&#xff0c;只有一个可以访问和更新共享数据。在单机系统我们可以使用 synchronized 锁、Lock 锁保证线程安全。 synchronized 锁是 Java 提供的一种内置锁&#xff0c;在单个 …

jenkins自动化脚本集成时钉钉消息未发送

在进行jenkins自动化脚本集成时&#xff0c;需要配置钉钉发送消息。钉钉的配置正确&#xff0c;测试钉钉消息发送成功&#xff0c;但是当构建项目时&#xff0c;却没有收到钉钉消息&#xff0c;报错如下&#xff1a; [钉钉插件]发送消息时报错: java.lang.NullPointerExceptio…

大转盘抽奖活动制作流程,让你轻松打造火爆营销活动

抽奖活动一直是商家吸引顾客、推广产品的利器之一。而如何让抽奖活动更加顺利、高效地进行呢&#xff1f;今天我们就要介绍的就是乔拓云平台&#xff0c;通过它&#xff0c;商家可以轻松地制作、发布抽奖活动&#xff0c;让您的营销更加便捷、迅速&#xff01;以下是具体操作步…

【智能电表数据接入物联网平台实践】

智能电表数据接入物联网平台实践 设备接线准备设备调试代码实现Modbus TCP Client 读取电表数据读取寄存器数据转成32bit Float格式然后使用modbusTCP Client 读取数据 使用mqtt协议接入物联网平台最终代码实现 设备接线准备 设备调试 代码实现 Modbus TCP Client 读取电表数…

音乐随行,公网畅享,群辉Audiostation给你带来听歌新体验!

文章目录 本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是本教程使用环境&#xff1a;1 群晖系统安装audiostation套件2 下载移动端app3 内网穿透&#xff0c;映射至公网 很多老铁想在上班路上听点喜欢的歌或者相声解解闷儿&#xff0c;于是打开手…

Go 多版本管理工具

Go 多版本管理工具 文章目录 Go 多版本管理工具一、go get 命令1.1 使用方法&#xff1a; 二、Goenv三、GVM (Go Version Manager)四、voidint/g4.1 安装4.2 冲突4.3 使用 在平时开发中&#xff0c;本地新旧项目并行开发的过程中&#xff0c;你大概率会遇到一个令人头疼的问题&…