当前位置: 首页 > news >正文

Spock Unit Test in Java

优质博文:IT-BLOG-CN
在这里插入图片描述

一、简介

Spock是一个基于Groovy语言的测试和规范框架,使得测试代码更简介,得益于JUnit RunnerSpock兼容大部分IDE和测试框架JUnit/JMock/Powermock等。基于BDD行为驱动开发,功能非常强大。提供了各种标签,并采用简单、通用、结构话描述语言,让编写测试代码更加简介、高效。官方文档

为什么要使用Spock:因为它优美而富有表现力的规范语言。Spock的灵感来自JUnitRSpecjMockMockitoGroovyScalaVulcans

主流单元测试框架比较

特性/框架JUnitMockitoPowerMockJMockEasyMockSpock
语言JavaJavaJavaJavaJavaGroovy(兼容Java)
主要用途单元测试、集成测试Mock对象的创建和验证Mock静态方法、构造函数和私有方法Mock对象的创建和验证Mock对象的创建和验证行为驱动开发(BDD)、单元测试、集成测试
BDD支持部分支持(通过扩展)不支持不支持不支持不支持原生支持
Mocking需要与Mockito或其他库结合原生支持Mock扩展Mockito,支持Mock静态方法和私有方法原生支持Mock原生支持Mock原生支持Mock|
数据驱动测试支持(需要额外的库,如JUnitParams不支持不支持不支持不支持原生支持
语言简洁性较为简洁,但需要一定的配置非常简介复杂(需要结合Mockito使用,配置较多)较为复杂(需要配置和学习JMock特有API)较为简洁,API清晰非常简介(DSL语法)
错误报告标准错误报告标准错误报告标准错误报告标准错误报告标准错误报告详细的错误和断言失败信息
IDE支持优秀(广泛支持)优秀(广泛支持)较好(但需要与Mockito结合)较好(但使用者较少)较好(广泛支持)良好(主流IDE支持,但部分功能可能不如JUnit完善
社区和生态系统非常成熟和广泛成熟和广泛较小(依赖Mockito的社区和生态系统)相对较少相对成熟相对较少,但在增长中
学习曲线低(大多数Java开发者熟悉)低(与JUnit结合使用时)高(需要学习Mockito和PowerMock的结合使用)中等(需要学习JMock API和配置)低(简单易学)中等(需要学习Groovy语法,但DSL使测试更直观
性能高性能高性能较高性能开销(复杂的Mock和字节码操作)高性能高性能较好的性能(但Groovy可能带来一些开销

二、优点

【1】简介且可读性强的语法: Spock使用Groovy语言编写测试脚本,其DSL领域特定语言使得测试代码非常简洁和可读。描述性的方法名:setup()/when()/then()使得测试逻辑一目了然。

内置多种标签来规范单元测试代码,使测试代码更规范、结构更清晰、可读性高、降低后续维护成本。

Spock是基于Groovy的测试框架,Groovy是一种在Java平台上的强大动态语言,简洁、灵活。相比PowerMock/JMock等框架需要在Java中编写,语法相对更加繁琐。Groovy的动态语言特性使得编写测试代码更加简洁和易读。

【2】数据驱动测试: Spock非常强大地支持数据驱动测试,通过where块可以方便地定义多组输入输出,减少重复代码,增加单元测试覆盖率。

【3】强加的错误抱错: Spock提供了详细的错误报告和断言失败信息,使得调试和修复问题更加容易。错误信息通常包含详细的上下文,使得定位问题更加直接。

【4】内置Mocking支持: Spock内置了MockingStubbing的功能,无需依赖第三方(如Mockito)。

【5】BDD风格支持: Spock天然支持行为驱动开发(BDD)风格的测试、这使得编写和维护测试变得更加直观。BDD风格的测试不仅描述了测试的行为,还能更好地表达业务逻辑,有助于提升代码质量。

三、 缺点

【1】IDE支持: 主流的IDE都支持Spock,但对于断点调试和代码补全等支持没有JUnit那样成熟。

【2】性能开销: 由于Spock使用Groovy作为脚本语言,可能会带来一定的性能开销。尽管开销大多数可以忽略,但是对性能极为敏感的场景下需要注意。

【3】社区生态较小: 虽然Spock功能强大,但相比JUnit/Spock的社区和生态系统相对较小。这意味着在遇到问题时,可用的资源和支持较少。

【4】学习曲线: 对于没有Groovy背景的开发者而言,学习和掌握Spock的语法需要一些时间。

四、环境配置

【1】pom依赖配置

<dependencyManagement><dependencies><dependency><groupId>org.spockframework</groupId><artifactId>spock-bom</artifactId><version>2.3-groovy-4.0</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement><dependencies><dependency><groupId>org.spockframework</groupId><artifactId>spock-core</artifactId><scope>test</scope></dependency><dependency><groupId>org.spockframework</groupId><artifactId>spock-junit4</artifactId><scope>test</scope></dependency>
</dependencies><plugins><!-- Mandatory plugins for using Spock --><plugin><!-- The gmavenplus plugin is used to compile Groovy code. To learn more about this plugin,visit https://github.com/groovy/GMavenPlus/wiki --><groupId>org.codehaus.gmavenplus</groupId><artifactId>gmavenplus-plugin</artifactId><version>3.0.2</version><executions><execution><goals><goal>compile</goal><goal>compileTests</goal></goals></execution></executions></plugin><!-- Optional plugins for using Spock --><!-- Only required if names of spec classes don't match default Surefire patterns (`*Test` etc.) --><plugin><artifactId>maven-surefire-plugin</artifactId><version>3.2.5</version><configuration><useFile>false</useFile><includes><include>**/*Test</include><include>**/*Spec</include></includes></configuration></plugin>
</plugins>

【2】Spock测试结构:测试类与规范。目录结构如下:

--src--main--test--groovy--com.flight.xxx(包名)--XXXSpec.groovy--XXXTest.groovy

五、测试方法的生命周期

junit使用时,主要用以下注解来标记测试类的方法:

@Test :标记需要运行的测试方法,一个测试类中可以有多个@Test方法;
@Before/@After :标记的方法,会在每个测试方法运行之前/之后运行一次;
@BeforeClass/@AfterClass :标记的方法会在测试类初始化时/销毁时运行;

spock没有使用以上的注解形式,而是测试类需要继承 Specification 父类,重写父类中的以下方法,就可以自定义测试方法的生命周期:

def setup() {}         // run before every feature method
def cleanup() {}       // run after every feature method
def setupSpec() {}     // run before the first feature method
def cleanupSpec() {}   // run after the last feature method

测试代码

package com.yawn.spockimport spock.lang.Shared
import spock.lang.Specification/*** spock 测试*/
class CalculateSpec extends Specification {// 初始化def setupSpec() {calculateService = new CalculateService()println ">>>>>>   setupSpec"}def setup() {println ">>>>>>   setup"}def cleanup() {println ">>>>>>   cleanup"}def cleanupSpec() {println ">>>>>>   cleanupSpec"}def "test life cycle"() {given:def a = 1def b = 2expect:a < bprintln "test method finished!"}
}

六、普通方法

【1】创建mock对象

def subscriber = Mock(Subscriber)
def subscriber2 = Mock(Subscriber)
Subscriber subscriber3 = Mock {1 * receive("hello")1 * receive("goodbye")
}Subscriber subscriber = Mock()
Subscriber subscriber2 = Mock()

【2】注入mock对象

class PublisherSpec extends Specification {Publisher publisher = new Publisher()Subscriber subscriber = Mock()Subscriber subscriber2 = Mock()def setup() {publisher.subscribers << subscriber // << is a Groovy shorthand for List.add()publisher.subscribers << subscriber2}
}

【3】调用频率

1 * subscriber.receive("hello") // exactly one call
0 * subscriber.receive("hello") // zero calls
(1..3) * subscriber.receive("hello") // between one and three calls (inclusive)
(1..) * subscriber.receive("hello") // at least one call
(..3) * subscriber.receive("hello") // at most three calls
_ * subscriber.receive("hello") // any number of calls, including zero
// (rarely needed; see 'Strict Mocking')

【4】目标约束

1 * subscriber.receive("hello") // a call to 'subscriber'
1 * _.receive("hello") // a call to any mock object

【5】方法约束

1 * subscriber.receive("hello") // a method named 'receive'
1 * subscriber./r.*e/("hello") // a method whose name matches the given regular expression (here: method name starts with 'r' and ends in 'e')

【6】参数约束

1 * subscriber.receive("hello") // an argument that is equal to the String "hello"
1 * subscriber.receive(!"hello") // an argument that is unequal to the String "hello"
1 * subscriber.receive() // the empty argument list (would never match in our example)
1 * subscriber.receive() // any single argument (including null)
1 * subscriber.receive(*) // any argument list (including the empty argument list)
1 * subscriber.receive(!null) // any non-null argument
1 * subscriber.receive(_ as String) // any non-null argument that is-a String
1 * subscriber.receive(endsWith("lo")) // any non-null argument that is-a String
1 * subscriber.receive({ it.size() > 3 && it.contains('a') })
// an argument that satisfies the given predicate, meaning that
// code argument constraints need to return true of false
// depending on whether they match or not
// (here: message length is greater than 3 and contains the character a)

【7】返回固定值

subscriber.receive(_) >> "ok"

【8】返回值序列:返回一个序列,迭代且依次返回指定值。如下所示,第一次调用返回ok,第二次调用返回error,以此类推

subscriber.receive(_) >>> ["ok", "error", "error", "ok"]

【9】动态计算返回值

subscriber.receive() >> { args -> args[0].size() > 3 ? "ok" : "fail" }
subscriber.receive() >> { String message -> message.size() > 3 ? "ok" : "fail" }

【10】产生异常

subscriber.receive(_) >> { throw new InternalError("ouch") }

【11】链式响应

subscriber.receive(_) >>> ["ok", "fail", "ok"] >> { throw new InternalError() } >> "ok"

【12】集成其他测试框架:Powermock集成

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(Sputnik.class)
@PrepareForTest([WorkContextFactory.class])
class NotificationDataNewCollectorTest extends Specification {
}

Mockito集成

@ExtendWith(MockitoExtension)
class MockStaticMethodSpec extends Specification {def "mock static method"() {given:def mock = Mockito.mockStatic(StringUtils)and:mock.when { StringUtils.equalsIgnoreCase(Mockito.any(), Mockito.any()) }.thenReturn(false)expect:result == StringUtils.equalsIgnoreCase(s1, s2)cleanup:mock.close()where:s1  | s2  || result"a" | "a" || false"a" | "b" || false}
}

七、静态方法

静态方法案例

public class TestClass {public static String staticMethod() {return null;}}

测试类:对于静态方法,私有方法,final方法,在用powermock做单元测试的时候,需要增加注解@PrepareForTest

这个注解的作用就是:该注释告诉PowerMock(ito)列出的类将需要在字节码级别上进行操作。

import org.junit.Rule
import org.mockito.Mockito
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.rule.PowerMockRule
import spock.lang.Specification@PrepareForTest([TestClass.class])
class MockStaticMethodSpec extends Specification {@RulePowerMockRule mPowerMockRule = new PowerMockRule();def "测试静态方法"() {setup :PowerMockito.mockStatic(TestClass.class)when :Mockito.when(TestClass.staticMethod()).thenReturn("测试用字串")then :TestClass.staticMethod() == "测试用字串"}}

相关文章:

Spock Unit Test in Java

优质博文&#xff1a;IT-BLOG-CN 一、简介 Spock是一个基于Groovy语言的测试和规范框架&#xff0c;使得测试代码更简介&#xff0c;得益于JUnit Runner&#xff0c;Spock兼容大部分IDE和测试框架JUnit/JMock/Powermock等。基于BDD行为驱动开发&#xff0c;功能非常强大。提…...

:= 符号python

在 Python 3.8 及更高版本中&#xff0c;引入了一种新的语法特性&#xff0c;称为"海象运算符"&#xff08;Walrus Operator&#xff09;&#xff0c;它使用 : 符号。这个运算符的主要目的是在表达式中同时进行赋值和返回赋值的值。 使用海象运算符可以在一些情况下…...

UPLOAD-LABS靶场[超详细通关教程,通关攻略]

---------------------------------------- 靶场环境&#xff1a; 下载链接&#xff1a; https://codeload.github.com/c0ny1/upload-labs/zip/refs/heads/master 使用小皮集成环境来完成这个靶场 将文件放到WWW目录下就可以进行访问 ------------------------------------…...

测试面试宝典(三十七)—— 接口测试中的加密参数如何处理?

1&#xff09;先了解接口使用的加密方式(md5、rsa...) 2&#xff09;检查接口测试工具是否支持这种加密方式&#xff0c;如果支持的话&#xff0c;直接使用对应功能就行了(比如Jmeter支持md5)&#xff1b;如果加密方式是公司内部特有的算法&#xff0c;可以在接口测试工具中调…...

秋招突击——7/23——百度提前批面试准备和正式面试

文章目录 引言一面准备面试预演一1、讲一下hashcode()和equals()关系2、equals()和有什么区别3、讲一下重载和重写的区别4、讲一下深拷贝、浅拷贝的区别5、讲一下Java异常的基类&#xff0c;运行时异常举几个例子&#xff0c;什么情况下会出现&#xff1f;6、讲一下Java中线程的…...

学习日记:数据类型2

目录 1.转义字符 2.隐式类型转换 2.1 强制类型转换 2.2 不同类型间赋值 3.运算符 表达式 3.1 算术运算符 3.2 算术运算优先级 3.3 赋值运算 3.3.1 不同类型间混合赋值 3.4 逗号运算 4.生成随机数 5. 每日一练 1.转义字符 \n 表示换行 \t …...

Django Web框架——05

文章目录 admin 后台数据库管理注册自定义模型类修改自定义模型类的展现样式模型管理器类再谈Meta类 数据表关联关系映射一对一映射一对多映射多对多映射 cookies 和 sessioncookiessessionCookies vs session admin 后台数据库管理 django 提供了比较完善的后台管理数据库的接…...

【React】项目的目录结构全面指南

文章目录 一、React 项目的基本目录结构1. node_modules2. public3. src4. App.js5. index.js6. .gitignore7. package.json8. README.md 二、React 项目的高级目录结构1. api2. hooks3. pages4. redux5. utils 三、最佳实践 在开发一个 React 项目时&#xff0c;良好的目录结构…...

Django学习(二)

get请求 练习&#xff1a; views.py def test_method(request):if request.method GET:print(request.GET)# 如果链接中没有参数a会报错print(request.GET[a])# 使用这个方法&#xff0c;当查询不到参数时&#xff0c;不会报错而是返回你设置的值print(request.GET.get(c,n…...

Java引用类型

强软弱虚 以 ZGC 为例&#xff0c;谈一谈 JVM 是如何实现 Reference 语义的 SoftReference 到底在什么时候被回收 &#xff1f; 如何量化内存不足 &#xff1f; PhantomReference 和 WeakReference 究竟有何不同 ThreadLocal 和 Netty ByteBuf中使用到的引用类型 https://w…...

ubunto安装redis

更新包管理工具 sudo apt update 安装Redis sudo apt install redis-server Redis已经安装并且服务已启动 sudo systemctl status redis-server Redis开机启动项 sudo systemctl enable redis-server 可以编辑配置文件 /etc/redis/redis.conf&#xff0c;然后重启Redis服务 比如…...

【odoo17 | Owl】前端js钩子调用列表选择视图

概要 在我们选择多对一或者多对多字段的时候&#xff0c;经常看到可以弹出列表弹窗让人一目了然的效果&#xff0c;效果如下&#xff1a; 那么&#xff0c;这种效果是odoo本身封装好的组件&#xff0c;我们在平时的前端界面开发的时候&#xff0c;既不是后端视图的情况下&#…...

MATLAB基础:函数与函数控制语句

今天我们继续学习Matlab中函数相关知识。 API的查询和调用 help 命令是最基本的查询方法&#xff0c;可查询所有目录、指定目录、命令、函数。 我们直接点击帮助菜单即可查询所需的API函数。 lookfor 关键字用于搜索相关的命令和函数。 如&#xff0c;我们输入lookfor inpu…...

2024.7.30 搜索插入位置(二分法)

题解 二分法 left和right标记二分区间 ans标记n&#xff0c;因为存在大于所有数的可能。 var searchInsert function(nums, target) {const n nums.length;let left 0, right n - 1, ans n;while (left < right) {//计算中位数let mid ((right - left) >> 1)…...

Socket通信(C++)

文章目录 什么是SocketSocket通信过程C Socket通信APIint socket(int domain, int type, int protocol);int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);struct sockaddrstruct sockaddr_unstruct sockaddr_in / struct sockaddr_in6 int connect(int …...

小白学大模型:LLaMA-Factory 介绍与使用

最近这一两周看到不少互联网公司都已经开始秋招提前批了。 不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友…...

java算法day26

java算法day26 207 课程表208 实现Trie(前缀树) 207 课程表 这题对应的知识是图论里的拓扑排序的知识。从题意就可以感受出来了。题目说如果要学习某课程&#xff0c;那么就需要先完成某课程。 这里我描述比较复杂的情况&#xff1a;课程与课程之间也有可能是多对一的场景或者…...

docker笔记7-dockerfile

docker笔记7-dockerfile 一、dockerfile介绍二、dockerfile指令三、构建自己的镜像 一、dockerfile介绍 Dockerfile是用来构建Docker镜像的构建文件&#xff0c;是由一系列命令和参数构成的脚本。 以下是常用的 Dockerfile 关键字的完整列表和说明&#xff1a; 二、docker…...

Spring-cloud Alibaba组件--Dubbo

远程调用技术 RestFul风格 基于HTTP协议实现&#xff0c;而HTTP是一种网络传输协议&#xff0c;基于TCP&#xff0c;规定了数据传输的格式。 RPC协议 Remote Produce Call 远程过程调用&#xff0c;类似的还有 RMI &#xff08; remote method invoke&#xff09;。自定义数…...

右值引用--C++11

左值引用和右值引用 传统的C语法中就有引用的语法&#xff0c;而C11中新增了的右值引用语法特性&#xff0c;所以从现在开始我们 之前学习的引用就叫做左值引用。无论左值引用还是右值引用&#xff0c;都是给对象取别名。 什么是左值&#xff1f;什么是左值引用&#xff1f;…...

这样做外贸报价表,客户看了才想下单

报价&#xff0c;是外贸业务中最重要的一步&#xff0c;作为外贸人&#xff0c;不会做报价表可不行。有人说&#xff0c;直接在邮件里回复价格不就好了&#xff1f;是的&#xff0c;产品简单的可以这么做&#xff0c;但你也不能忽视报价表的价值&#xff0c;一份完美的价格表对…...

Swift学习入门,新手小白看过来

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…...

【Ant Design Pro】快速上手

初始化 初始化脚手架&#xff1a;快速开始 官方默认使用 umi4&#xff0c;这里文档还没有及时更新&#xff08;不能像文档一样选择 umi 的版本&#xff09;&#xff0c;之后我选择 simple。 然后安装依赖。 在 package.json 中&#xff1a; "start": "cross-e…...

Hive3:Hive初体验

1、创建表 CREATE TABLE test(id INT, name STRING, gender STRING);2、新增数据 INSERT INTO test VALUES(1, 王力红, 男); INSERT INTO test VALUES(2, 钉钉盯, 女); INSERT INTO test VALUES(3, 咔咔咔, 女);3、查询数据 简单查询 select * from test;带聚合函数的查询 …...

blender顶点乱飞的问题解决

初学blender&#xff0c;编辑模式下移动某些顶点&#xff0c;不管是移动还是滑动都会出现定点乱飞的问题&#xff0c;后来才发现是开了吸附工具的原因&#xff01;&#xff01;&#xff01;&#xff01; 像下面这样&#xff0c;其实我只是在Z轴上移动&#xff0c;但是就跑的很…...

Elasticsearch(ES) 集群脑裂

脑裂问题(split-brain problem)是指一个分布式系统中&#xff0c;当网络分裂&#xff08;network partition&#xff09;发生时&#xff0c;导致系统内部的两个或多个节点相互独立地认为自己仍然与其他节点连接&#xff0c;每个节点组都试图执行操作&#xff0c;这可能会导致数…...

spark 3.0.0源码环境搭建

环境 Spark版本&#xff1a;3.0.0 java版本&#xff1a;1.8 scala版本&#xff1a;2.12.19 Maven版本&#xff1a;3.8.1 编译spark 将spark-3.0.0的源码导入到idea中 执行mvn clean package -Phive -Phive-thriftserver -Pyarn -DskipTests 执行sparksql示例类SparkSQLExam…...

3.3、matlab彩色图和灰度图的二值化算法汇总

1、彩色图和灰度图的二值化算法汇总原理及流程 彩色图和灰度图的二值化算法的原理都是将图像中的像素值转化为二值(0或1),以便对图像进行简化或者特定的图像处理操作。下面分别介绍彩色图和灰度图的二值化算法的原理及流程: 1)彩色图的二值化算法原理及流程 (1)原理:…...

新手必看:Elasticsearch 入门全指南

Elasticsearch 入门介绍 Elasticsearch 是一个开源的分布式搜索和分析引擎&#xff0c;广泛应用于处理大规模数据和实时搜索需求。它基于 Apache Lucene 构建&#xff0c;具备高可扩展性和分布式特性&#xff0c;能够快速、可靠地存储、搜索和分析大量数据。本文将介绍 Elasti…...

【Linux】TCP全解析:构建可靠的网络通信桥梁

文章目录 前言1. TCP 协议概述2. TCP报头结构3. 如何理解封装和解包呢&#xff1f;4. TCP的可靠性机制4.1 TCP的确认应答机制4.2 超时重传机制 5. TCP链接管理机制5.1 经典面试题&#xff1a;为什么建立连接是三次握手&#xff1f;5.2 经典面试题&#xff1a;为什么要进行四次挥…...

图像处理 -- ISP中的3DNR与2DNR区别及实现原理

ISP中的3DNR与2DNR区别及实现原理 2DNR&#xff08;2D Noise Reduction&#xff09; 2DNR的原理&#xff1a; 2DNR主要针对单帧图像进行降噪处理。它利用空间域内的像素值&#xff0c;采用空间滤波的方法来减少噪声。常用的方法包括均值滤波、中值滤波和高斯滤波等。这些方法…...

硬盘分区读不出来的解决之道:从自救到专业恢复

在日常的计算机使用过程中&#xff0c;硬盘分区读不出来的问题常常令人头疼不已。这一问题不仅阻碍了用户对数据的正常访问&#xff0c;还可能预示着数据安全的潜在威胁。硬盘分区读不出来&#xff0c;通常是由于分区表损坏、文件系统错误、物理扇区损坏、驱动程序冲突或硬件连…...

盘点2024年网上很火的4个语音识别转文字工具。

语音识别转文字是一项非常实用的技术&#xff0c;可以帮助我们在会议记录中省去手动记录&#xff0c;在采访中迅速得到文字稿&#xff0c;在学习中快速生成课堂笔...运用十分广泛。但是很多人不知道要怎么转换&#xff0c;在这里我便给大家介绍几款效率非常高的语音转文字的工具…...

解决 Git 访问 GitHub 时的 SSL 错误

引言 在使用 Git 进行版本控制时&#xff0c;我们可能会遇到各种网络相关的错误。其中一种常见的错误是 SSL 连接问题&#xff0c;这会导致 Git 无法访问远程仓库。本文将介绍一个具体的错误 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0&#xff0c;以及如何通过禁用 SSL 证…...

LinuxCentos中安装apache网站服务详细教程

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f427;Linux基础知识(初学)&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; &#x1f510;Linux中firewalld防火墙&#xff1a;点击&#xff01; ⏰️创作…...

LUA脚本改造redis分布式锁

在redis集群模式下&#xff0c;我们会启动多个tomcat实例&#xff0c;每个tomcat实例都有一个JVM&#xff0c;且不共享。而synchronize锁的作用范围仅仅是当前JVM&#xff0c;所以我们需要一个作用于集群下的锁&#xff0c;也就是分布式锁。&#xff08;就是不能用JVM自带的锁了…...

web端使用HTML5开发《贪吃蛇》小游戏教程【附源码】

自制游戏列表 1植物大战僵尸自制HTML5游戏《植物大战僵尸》2开心消消乐自制HTML5游戏《开心消消乐》3贪吃蛇自制HTML5游戏《贪吃蛇》4捕鱼达人自制HTML5游戏《捕鱼达人》 一、游戏简介 贪吃蛇是一款经典的电子游戏&#xff0c;最早在1976年由Gremlin公司推出&#xff0c;名为…...

Selenium使用教程-Selenium环境搭建与基础操作

Selenium环境搭建与基础操作 1. 引言&#xff1a;Selenium简介​ Selenium&#xff0c;作为自动化测试领域的明星工具&#xff0c;以其强大的跨浏览器测试能力而闻名。它支持多种编程语言&#xff08;如Java、Python、C#等&#xff09;&#xff0c;允许开发者编写脚本来模拟真…...

1950年-2021年中国历年民航航线里程统计报告

数据为1950年到2021年我国每年的民航航线总里程数据。 2021年&#xff0c;我国定期航班航线总里程为689.78万公里&#xff0c;相比2019年下降了258.44万公里。 数据统计单位为&#xff1a;公里. 数据说明&#xff1a; 2011年起民航航线里程改为定期航班航线里程 我国定期航班…...

前端了解到框架-网络复习

前端 HTML 超文本标记语言 画页面 各种各样的标签组成页面进行展示 桌面创建文本修改后缀即可 <!DOCTYPE html>: 声明文档类型和HTML版本。<html>: 根标签&#xff0c;所有其他标签都包含在内。<head>: 包含了文档的元数据&#xff0c;如字符编码、网页标…...

防火墙——网络环境支持

目录 网络环境支持 防火墙的组网 web连接上防火墙 web管理口 让防火墙接到网络环境中 ​编辑 管理员用户管理 缺省管理员 接口 配置一个普通接口 创建安全区域 路由模式 透明模式 混合模式 防火墙的安全策略 防火墙转发流程 与传统包过滤的区别 创建安全策略 …...

阅读笔记:明朝那些事儿之拐弯中的帝国

​万历皇帝时期内阁首辅&#xff1a; 张居正&#xff0c;申时行&#xff0c;王锡爵&#xff0c;许国&#xff0c;王家屏&#xff0c;赵志皋&#xff08;给皇帝写辞职信没有回音&#xff0c;自己不告而回家&#xff09;&#xff0c;沈一贯&#xff0c;于慎行&#xff0c;叶向高…...

React基础知识 精简全面 推荐

这篇博文主要对一些刚入门react框架的同学&#xff0c;以及对react基本知识进行巩固的&#xff0c;最后就是精简一下基本知识&#xff0c;以方便自己查看&#xff0c;感谢参考&#xff0c;有问题评论区交流&#xff0c;谢谢。 目录 1.JSX 2.Props 和 State 3.组件生命周期…...

OV SSL证书申请指南

OV SSL证书除了验证域名所有权外还需要验证组织信息&#xff0c;这类证书适用于对公司官网、品牌、安全性等有较高程度要求的企业级用户。具体申请流程如下&#xff1a; 一 、注册账号 注册账号填写230919注册码即可获得大额优惠券和全程一对一技术支持https://www.joyssl.co…...

变色树脂的变色原理?变色树脂在水处理中的应用?

变色树脂是一种具有特殊功能的高分子材料&#xff0c;能够在特定条件下改变其颜色&#xff0c;从而指示环境变化&#xff08;如pH值、温度、特定离子浓度等&#xff09;或反应进程。这类树脂通常含有能够响应特定刺激的化学结构&#xff0c;通过化学反应、离子交换、分子构象变…...

16 敏捷开发实践(1)

敏捷方法&#xff1a;是一种从1990年代开始逐渐引起广泛关注的一些新型软件开发方法&#xff0c;是一种应对快速变化的需求的一种软件开发能力。 敏捷开发&#xff1a;是一种以人为核心、迭代、循序渐进的开发方法。 敏捷实践&#xff1a;精益软件开发&#xff08;LSD&#x…...

如何使用虚拟机如何安装 Kali Linux ?

1.下载虚拟机&#xff1a;https://www.virtualbox.org/wiki/Downloads 选择你的系统版本 2.下载kali linux系统镜像&#xff1a;https://www.kali.org/get-kali/#kali-virtual-machines 全部下载完成后&#xff0c;我们会得到以下文件&#xff01; 1.压缩Kali Linux压缩包 2.安…...

Yarn UI 时间问题,相差8小时

位置 $HADOOP_HOME/share/hadoop/yarn/hadoop-yarn-common-2.6.1.jar 查看 jar tf hadoop-yarn-common-2.6.1.jar |grep yarn.dt.plugins.js webapps/static/yarn.dt.plugins.js 解压 jar -xvf hadoop-yarn-common-2.6.1.jar webapps/static/yarn.dt.plugins.js inflated: we…...

【JavaWeb项目】——外卖订餐系统之登入、登入后显示餐品信息、用户注册、注销部分

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…...

怎么保护电脑文件夹?文件夹保护方法大盘点

文件夹是管理电脑数据的重要工具&#xff0c;可以有效避免数据混乱。而为了避免文件夹数据泄露&#xff0c;我们需要严格保护文件夹。下面我们就来盘点一下文件夹的保护方法。 文件夹隐藏 隐藏文件夹是一种简单有效的保护方式&#xff0c;通过隐藏文件夹来避免其他人发现&…...