第二节 zookeeper基础应用与实战

目录

1. Zookeeper命令操作

1.1 Zookeeper 数据模型

1.2 Zookeeper服务端常用命令

1.3 Zookeeper客户端常用命令

1.3.1 基本CRUD

1.3.2 创建临时&顺序节点

2. Zookeeper JavaAPI操作

2.1 Curator介绍

2.2 引入Curator

2.3 建立连接

2.4 添加节点

2.5 修改节点

2.6 删除节点

2.7 Watch事件监听

2.7.1 zkCli客户端使用watch

2.7.2 curator客户端使用watch


1. Zookeeper命令操作

1.1 Zookeeper 数据模型

ZooKeeper 是一个树形目录服务,其数据模型和Unix的文件系统目录树很类似,拥有一个层次化结构。

image.png

Zookeeper这里面的每一个节点都被称为: ZNode,每个节点上都会保存自己的数据和节点信息。

image.png

节点可以拥有子节点,同时也允许少量(1MB)数据存储在该节点之下。

节点可以分为四大类:

  • PERSISTENT 持久化节点

  • EPHEMERAL 临时节点 :-e

  • PERSISTENT_SEQUENTIAL 持久化顺序节点 :-s

  • EPHEMERAL_SEQUENTIAL 临时顺序节点 :-es

1.2 Zookeeper服务端常用命令

image.png

•启动 ZooKeeper 服务

./zkServer.sh start

•查看 ZooKeeper 服务状态

./zkServer.sh status

•停止 ZooKeeper 服务

./zkServer.sh stop 

•重启 ZooKeeper 服务

./zkServer.sh restart 

1.3 Zookeeper客户端常用命令

1.3.1 基本CRUD

  • 连接Zookeeper客户端

# 本地连接
zkCli.sh
​
# 远程连接
zkCli.sh -server ip:2181
  • 断开连接

quit
  • 查看命令帮助

help
  • 显示制定目录下节点

# ls 目录
ls /
  • 创建节点

# create /节点path value
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] create /app1 msb123
Created /app1
[zk: localhost:2181(CONNECTED) 2] ls /
[app1, zookeeper]
[zk: localhost:2181(CONNECTED) 3] create /app2
Created /app2
[zk: localhost:2181(CONNECTED) 4] ls /
[app1, app2, zookeeper]
  • 获取节点值

# get /节点path
[zk: localhost:2181(CONNECTED) 15] get /app1
msb123
[zk: localhost:2181(CONNECTED) 16] get /app2
null
  • 设置节点值

# set /节点path value
[zk: localhost:2181(CONNECTED) 17] set /app2 msb456
[zk: localhost:2181(CONNECTED) 18] get /app2
msb456
  • 删除单个节点

# delete /节点path
[zk: localhost:2181(CONNECTED) 19] delete /app2
[zk: localhost:2181(CONNECTED) 20] get /app2
Node does not exist: /app2
[zk: localhost:2181(CONNECTED) 21] ls /
[app1, zookeeper]
  • 删除带有子节点的节点

# deleteall /节点path
[zk: localhost:2181(CONNECTED) 22] create /app1
Node already exists: /app1
[zk: localhost:2181(CONNECTED) 23] create /app1/p1
Created /app1/p1
[zk: localhost:2181(CONNECTED) 24] create /app1/p2
Created /app1/p2
[zk: localhost:2181(CONNECTED) 25] delete /app1
Node not empty: /app1
[zk: localhost:2181(CONNECTED) 26] deleteall /app1
[zk: localhost:2181(CONNECTED) 27] ls /
[zookeeper]

1.3.2 创建临时&顺序节点

  • 创建临时节点 (-e)

    • 临时节点是在会话结束后,自动被删除的

# create -e /节点path value
[zk: localhost:2181(CONNECTED) 29] create -e /app1 msb123
Created /app1
[zk: localhost:2181(CONNECTED) 30] get /app1
msb123
[zk: localhost:2181(CONNECTED) 31] quit# 退出后再次连接,临时节点已经删除
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
  • 创建顺序节点 (-s)

    • 创建出的节点,根据先后顺序,会在节点之后带上一个数值,越后执行数值越大,适用于分布式锁的应用场景- 单调递增.

# create -s /节点path value
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] create -s /app2
Created /app20000000003
[zk: localhost:2181(CONNECTED) 2] ls /
[app20000000003, zookeeper]
[zk: localhost:2181(CONNECTED) 3] create -s /app2 
Created /app20000000004
[zk: localhost:2181(CONNECTED) 4] ls /
[app20000000003, app20000000004, zookeeper]
[zk: localhost:2181(CONNECTED) 5] create -s /app2 
Created /app20000000005
[zk: localhost:2181(CONNECTED) 6] ls /
[app20000000003, app20000000004, app20000000005, zookeeper]# 创建临时顺序节点
[zk: localhost:2181(CONNECTED) 7] create -es /app3
Created /app30000000006
[zk: localhost:2181(CONNECTED) 8] ls /
[app20000000003, app20000000004, app20000000005, app30000000006, zookeeper]
# 退出
[zk: localhost:2181(CONNECTED) 9] quit# 重新链接,临时顺序节点已经被删除
[zk: localhost:2181(CONNECTED) 0] ls /
[app20000000003, app20000000004, app20000000005, zookeeper]

image.png

  • 查询节点详细信息

# ls –s /节点path 
[zk: localhost:2181(CONNECTED) 5] ls / -s
[app20000000003, app20000000004, app20000000005, zookeeper]
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x14
cversion = 10
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 4
  • czxid:节点被创建的事务ID

  • ctime: 创建时间

  • mzxid: 最后一次被更新的事务ID

  • mtime: 修改时间

  • pzxid:子节点列表最后一次被更新的事务ID

  • cversion:子节点的版本号

  • dataversion:数据版本号

  • aclversion:权限版本号

  • ephemeralOwner:用于临时节点,代表临时节点的事务ID,如果为持久节点则为0

  • dataLength:节点存储的数据的长度

  • numChildren:当前节点的子节点个数

2. Zookeeper JavaAPI操作

2.1 Curator介绍

Curator是Netflix公司开源的一套zookeeper客户端框架,Curator是对Zookeeper支持最好的客户端框架。Curator封装了大部分Zookeeper的功能,比如Leader选举、分布式锁等,减少了技术人员在使用Zookeeper时的底层细节开发工作。

Curator框架主要解决了三类问题:

  • 封装ZooKeeper Client与ZooKeeper Server之间的连接处理(提供连接重试机制等)。

  • 提供了一套Fluent风格的API,并且在Java客户端原生API的基础上进行了增强(创捷多层节点、删除多层节点等)。

  • 提供ZooKeeper各种应用场景(分布式锁、leader选举、共享计数器、分布式队列等)的抽象封装。

2.2 引入Curator

  • 创建maven项目,引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mashibing</groupId><artifactId>zk-client1</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version><scope>test</scope></dependency><!--curator--><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.0.0</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.0.0</version></dependency><!--日志--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build>
</project>

2.3 建立连接

方式1

public class CuratorTest {/*** 建立连接*/@Testpublic void testConnect(){/*** String connectString     连接字符串。 zk地址和端口: "192.168.58.100:2181,192.168.58.101:2181"* int sessionTimeoutMs     会话超时时间 单位ms* int connectionTimeoutMs  连接超时时间 单位ms* RetryPolicy retryPolicy  重试策略*///1. 第一种方式//重试策略 baseSleepTimeMs 重试之间等待的初始时间,maxRetries 重试的最大次数RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10);CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.58.100:2181", 60 * 1000,15 * 1000, retryPolicy);//开启连接client.start();}
}

重试策略

  • RetryNTimes: 重试没有次数限制

  • RetryOneTime:只重试没有次数限制,一般也不常用

  • ExponentialBackoffRetry: 只重试一次的重试策略

方式2

public class CuratorTest {private CuratorFramework client;/*** 建立连接*/@Testpublic void testConnect(){/*** String connectString     连接字符串。 zk地址和端口: "192.168.58.100:2181,192.168.58.101:2181"* int sessionTimeoutMs     会话超时时间 单位ms* int connectionTimeoutMs  连接超时时间 单位ms* RetryPolicy retryPolicy  重试策略*///1. 第一种方式//重试策略 baseSleepTimeMs 重试之间等待的初始时间,maxRetries 重试的最大次数RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10);//      client   = CuratorFrameworkFactory.newClient("192.168.58.100:2181", 60 * 1000,
//                15 * 1000, retryPolicy);//2. 第二种方式,建造者方式创建client = CuratorFrameworkFactory.builder().connectString("192.168.58.100:2181").sessionTimeoutMs(60*1000).connectionTimeoutMs(15 * 1000).retryPolicy(retryPolicy).namespace("mashibing")  //根节点名称设置.build();//开启连接client.start();}
}

2.4 添加节点

修改testConnect注解,@Before

   /*** 建立连接*/@Beforepublic void testConnect()

创建节点:create 持久 临时 顺序 数据

public class CuratorTest {/*** 创建节点 create 持久 临时 顺序 数据*///1.创建节点@Testpublic void testCreate1() throws Exception {// 如果没有创建节点,没有指定数据,则默认将当前客户端的IP 作为数据存储String path = client.create().forPath("/app1");System.out.println(path);}@Afterpublic void close(){client.close();}
}

image.png

    //2.创建节点 带有数据@Testpublic void testCreate2() throws Exception {String path = client.create().forPath("/app2","hehe".getBytes());System.out.println(path);}

image.png

    //3.设置节点类型 默认持久化@Testpublic void testCreate3() throws Exception {//设置临时节点String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3");System.out.println(path);}

由于是临时节点,需要打断点才能看到节点信息

image.png

//1.查询数据 getData
@Test
public void testGet1() throws Exception {byte[] data = client.getData().forPath("/app1");System.out.println(new String(data));
}//2.查询子节点 getChildren()
@Test
public void testGet2() throws Exception {List<String> path = client.getChildren().forPath("/");System.out.println(path);
}//3.查询节点状态信息
@Test
public void testGet3() throws Exception {Stat status = new Stat();System.out.println(status);//查询节点状态信息: ls -sclient.getData().storingStatIn(status).forPath("/app1");System.out.println(status);
}

2.5 修改节点

    //1. 基本数据修改@Testpublic void testSet() throws Exception {client.setData().forPath("/app1","hahaha".getBytes());}//根据版本修改(乐观锁)@Testpublic void testSetVersion() throws Exception {//查询版本Stat status = new Stat();//查询节点状态信息: ls -sclient.getData().storingStatIn(status).forPath("/app1");int version = status.getVersion();System.out.println(version);  //2client.setData().withVersion(version).forPath("/app1","hehe".getBytes());}

image.png

2.6 删除节点

    //1.删除单个节点@Testpublic void testDelete1() throws Exception {client.delete().forPath("/app4");}//删除带有子节点的节点@Testpublic void testDelete2() throws Exception {client.delete().deletingChildrenIfNeeded().forPath("/app4");}//必须删除成功(超时情况下,重试删除)@Testpublic void testDelete3() throws Exception {client.delete().guaranteed().forPath("/app2");}//回调 删除完成后执行@Testpublic void testDelete4() throws Exception {client.delete().guaranteed().inBackground((curatorFramework, curatorEvent) -> {System.out.println("我被删除了");System.out.println(curatorEvent);}).forPath("/app1");}

2.7 Watch事件监听

ZooKeeper 允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 ZooKeeper 实现分布式协调服务的重要特性。

ZooKeeper 中引入了Watcher机制来实现了发布/订阅功能能,能够让多个订阅者同时监听某一个对象,当一个对象自身状态变化时,会通知所有订阅者。

image.png

2.7.1 zkCli客户端使用watch

添加 -w 参数可实时监听节点与子节点的变化,并且实时收到通知。非常适用保障分布式情况下的数据一至性。

其使用方式如下

命令描述
ls -w path监听子节点的变化(增,删) [监听目录]
get -w path监听节点数据的变化
stat -w path监听节点属性的变化

Zookeeper事件类型

  • NodeCreated: 节点创建

  • NodeDeleted: 节点删除

  • NodeDataChanged:节点数据变化

  • NodeChildrenChanged:子节点列表变化

  • DataWatchRemoved:节点监听被移除

  • ChildWatchRemoved:子节点监听被移除

1)get -w path 监听节点数据变化

  • 会话1

    image.png

  • 会话2

    image.png

  • 再回到会话一

    image.png

2) ls -w /path 监听子节点的变化(增,删) [监听目录]

  • 会话1

    image.png

  • 会话2

    image.png

  • 切到【会话一】 观察输出的监听日志

    image.png

当然了 delete 目录,也会发生变化

如果对节点数据内容,ls -w 是收不到通知的,只能通过 get -w来实现 。

这里,监听一点触发,就失效了,切记。

3) ls -R -w /path 例子二 循环递归的监听

image.png

image.png

2.7.2 curator客户端使用watch

ZooKeeper 原生支持通过注册Watcher来进行事件监听,但是其使用并不是特别方便需要开发人员自己反复注册Watcher,比较繁琐。

Curator引入了 Cache 来实现对 ZooKeeper 服务端事件的监听。

ZooKeeper提供了三种Watcher:

  • NodeCache : 只是监听某一个特定的节点

  • PathChildrenCache : 监控一个ZNode的子节点.

  • TreeCache : 可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCache的组合

1)watch监听 NodeCache

public class CuratorWatchTest {/*** 演示 NodeCache : 给指定一个节点注册监听*/@Testpublic void testNodeCache() throws Exception {//1. 创建NodeCache对象NodeCache nodeCache = new NodeCache(client, "/app1");  //监听的是 /mashibing和其子目录app1//2. 注册监听nodeCache.getListenable().addListener(new NodeCacheListener() {@Overridepublic void nodeChanged() throws Exception {System.out.println("节点变化了。。。。。。");//获取修改节点后的数据byte[] data = nodeCache.getCurrentData().getData();System.out.println(new String(data));}});//3. 设置为true,开启监听nodeCache.start(true);while(true){}} 
}

image.png

2)watch监听 PathChildrenCache

    /*** 演示 PathChildrenCache: 监听某个节点的所有子节点*/@Testpublic void testPathChildrenCache() throws Exception {//1.创建监听器对象 (第三个参数表示缓存每次节点更新后的数据)PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app2", true);//2.绑定监听器pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {@Overridepublic void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {System.out.println("子节点发生变化了。。。。。。");System.out.println(pathChildrenCacheEvent);if(PathChildrenCacheEvent.Type.CHILD_UPDATED == pathChildrenCacheEvent.getType()){//更新子节点System.out.println("子节点更新了!");//在一个getData中有很多数据,我们只拿data部分byte[] data = pathChildrenCacheEvent.getData().getData();System.out.println("更新后的值为:" + new String(data));}else if(PathChildrenCacheEvent.Type.CHILD_ADDED == pathChildrenCacheEvent.getType()){//添加子节点System.out.println("添加子节点!");String path = pathChildrenCacheEvent.getData().getPath();System.out.println("子节点路径为: " + path);}else if(PathChildrenCacheEvent.Type.CHILD_REMOVED == pathChildrenCacheEvent.getType()){//删除子节点System.out.println("删除了子节点");String path = pathChildrenCacheEvent.getData().getPath();System.out.println("子节点路径为: " + path);}}});//3. 开启pathChildrenCache.start();while(true){}}

image.png

事件对象信息分析

PathChildrenCacheEvent{type=CHILD_UPDATED, data=ChildData{path='/app2/m1', stat=164,166,1670114647087,1670114698259,1,0,0,0,3,0,164, data=[49, 50, 51]}
}

image.png

3)watch监听 TreeCache

TreeCache相当于NodeCache(只监听当前结点)+ PathChildrenCache(只监听子结点)的结合版,即监听当前和子结点。

  /*** 演示 TreeCache: 监听某个节点的所有子节点*/@Testpublic void testCache() throws Exception {//1.创建监听器对象TreeCache treeCache = new TreeCache(client, "/app2");//2.绑定监听器treeCache.getListenable().addListener(new TreeCacheListener() {@Overridepublic void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {System.out.println("节点变化了");System.out.println(treeCacheEvent);if(TreeCacheEvent.Type.NODE_UPDATED == treeCacheEvent.getType()){//更新节点System.out.println("节点更新了!");//在一个getData中有很多数据,我们只拿data部分byte[] data = treeCacheEvent.getData().getData();System.out.println("更新后的值为:" + new String(data));}else if(TreeCacheEvent.Type.NODE_ADDED == treeCacheEvent.getType()){//添加子节点System.out.println("添加节点!");String path = treeCacheEvent.getData().getPath();System.out.println("子节点路径为: " + path);}else if(TreeCacheEvent.Type.NODE_REMOVED == treeCacheEvent.getType()){//删除子节点System.out.println("删除节点");String path = treeCacheEvent.getData().getPath();System.out.println("删除节点路径为: " + path);}}});//3. 开启treeCache.start();while(true){}}

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

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

相关文章

[2024]常用的pip指令

[2024]常用的pip指令 HI&#xff0c;这里是肆十二&#xff0c;好久不见&#xff0c;大家&#xff01; 新年好&#xff01; pip是Python的包管理工具&#xff0c;它可以用来安装、升级、卸载Python包。以下是一些常用的pip指令&#xff1a; 安装包&#xff1a; bash复制代码…

mac电脑安装cocoapods出错,以及安装最新版本ruby方法

macbook安装cocoapods时碰到一个报错&#xff1a;大概率是ruby的版本太低导致的 sudo gem install cocoapods ERROR: Error installing cocoapods: ERROR: Failed to build gem native extension. ... Could not create Makefile due to some reason, probably lack of neces…

【深度学习每日小知识】全景分割

全景分割 全景分割是一项计算机视觉任务&#xff0c;涉及将图像或视频分割成不同的对象及其各自的部分&#xff0c;并用相应的类别标记每个像素。与传统的语义分割相比&#xff0c;它是一种更全面的图像分割方法&#xff0c;传统的语义分割仅将图像划分为类别&#xff0c;而不…

openstack(T版)公有云--Dashboard服务

公有云上OpenStack Train最小化安装_openstack最小化部署-CSDN博客 我的opensatck(T)是参考上面链接去部署完成的&#xff0c;在部署完Dashboard服务后&#xff0c;将要用浏览器访问的时候出现了404 500 Internal Server Error 等各种各样的问题&#xff0c;以下是我排查问题…

编程实例分享,宠物诊所电子处方怎么开,兽医电子处方模板电子版操作教程

编程实例分享&#xff0c;宠物诊所电子处方怎么开&#xff0c;兽医电子处方模板电子版操作教程 一、前言 以下操作教程以 佳易王兽医电子处方软件V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、在系统 设置里可以设置打印参数&#x…

英语语法-八大时态

目录 一般现在时 一般过去时 一般将来时 现在进行时 过去进行时 现在完成时 过去完成时 过去将来时 一般现在时 I do my homework at 7.我平时都在7点写作业。 dont和didnt都表示否定&#xff0c;如何区分用法呢&#xff0c;dont表示一般现在时&#xff0c;表示平时也…

从零开始学howtoheap:fastbins的house_of_spirit攻击3

how2heap是由shellphish团队制作的堆利用教程&#xff0c;介绍了多种堆利用技术&#xff0c;后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境&#xff1a;从零开始配置pwn环境&#xff1a;从零开始配置pwn环境&#xff1a;优化pwn虚拟机配置支持libc等指…

Linux操作系统下安装消息中间件RabbitMQ_00000

下载 在官网下载Linux版RabbitMQ安装文件。 erlang-21.3-1.el7.x86_64.rpm rabbitmq-server-3.8.8-1.el7.noarch.rpm 安装 1、将文件上传至Linux系统中。 上传到/usr/local/software目录下&#xff08;如果没有software目录&#xff0c;则创建。&#xff09;。 2、安装文件&…

Linux下的socket操作

一、TCP服务端 创建一个TCP服务器的基本操作&#xff1a; 创建一个套接字&#xff08;socket&#xff09;&#xff1a;使用socket函数绑定套接字&#xff08;socket&#xff09;:将套接字绑定到一个特定的IP地址和端口号上&#xff0c;这些信息要用结构体sockaddr_in来保存监…

小游戏和GUI编程(3) | 基于 SFML 的字符阵

小游戏和GUI编程(3) | 基于 SFML 的字符阵 1. 简介 使用 EasyX 图形库时&#xff0c; 官方第一个例子是字符阵。 EasyX 不开源&#xff0c; 也不能跨平台&#xff0c; API 陈旧&#xff0c; API 是 C 而不是 C。 现在使用 SFML 来实现字符阵&#xff0c; 克服 EasyX 的这些问…

MySQL温故篇(一)SQL语句基础

一、SQL语句基础 数据库&#xff08;SQL&#xff09;思维导图_数据库设计思维导图-CSDN博客 1、SQL语言分类 DDL&#xff1a;数据定义语言 DCL&#xff1a;数据控制语言 DML&#xff1a;数据操作语言 DQL&#xff1a;数据的查询语言 2、数据类型 3、字符类型 char(11) &…

蓝桥杯Web应用开发-CSS3 新特性

CSS3 新特性 专栏持续更新中 在前面我们已经学习了元素选择器、id 选择器和类选择器&#xff0c;我们可以通过标签名、id 名、类名给指定元素设置样式。 现在我们继续选择器之旅&#xff0c;学习 CSS3 中新增的三类选择器&#xff0c;分别是&#xff1a; • 属性选择器 • 子…

《CSS 简易速速上手小册》第8章:CSS 性能优化和可访问性(2024 最新版)

文章目录 8.1 CSS 文件的组织和管理8.1.1 基础知识8.1.2 重点案例&#xff1a;项目样式表结构8.1.3 拓展案例 1&#xff1a;使用BEM命名规范8.1.4 拓展案例 2&#xff1a;利用 Sass 混入创建响应式工具类 8.2 提高网页加载速度的技巧8.2.1 基础知识8.2.2 重点案例&#xff1a;图…

C#,泰波拿契数(Tribonacci Number)的算法与源代码

1 泰波拿契数&#xff08;Tribonacci Number&#xff09; 泰波拿契数&#xff08;Tribonacci Number&#xff09;是斐波那契的拓展。 泰波拿契数 (Tribonacci Number) 即把费波拿契数 (Fibonacci Number) 的概念推广至三个数。 2 计算结果 3 源程序 using System; namespace…

Java安全 CC链1分析(Lazymap类)

Java安全 CC链1分析 前言CC链分析CC链1核心LazyMap类AnnotationInvocationHandler类 完整exp&#xff1a; 前言 在看这篇文章前&#xff0c;可以看下我的上一篇文章&#xff0c;了解下cc链1的核心与环境配置 Java安全 CC链1分析 前面我们已经讲过了CC链1的核心ChainedTransf…

[C/C++] -- Boost库、Muduo库编译安装使用

1.Muduo库 Muduo 是一个基于 C11 的高性能网络库&#xff0c;其核心是事件驱动、非阻塞 I/O、线程池等技术&#xff0c;以实现高并发、高性能的网络通信。Muduo 库主要由陈硕先生开发维护&#xff0c;已经成为 C 服务器程序员的常用工具之一。 Muduo 库的主要特点&#xff1a…

M1 Mac使用SquareLine-Studio进行LVGL开发

背景 使用Gui-Guider开发遇到一些问题&#xff0c;比如组件不全。使用LVGL官方的设计软件开发 延续上一篇使用的基本环境。 LVGL项目 新建项目 选择Arduino的项目&#xff0c;设定好分辨率及颜色。 设计UI 导出代码 Export -> Create Template Project 导出文件如图…

使用client-only 解决组件不兼容SSR问题

目录 前言 一、解决方案 1.基于Nuxt 框架的SSR应用 2.基于vue2框架的应用 3.基于vue3框架的应用 二、总结 往期回顾 前言 最近在我的单页面SSR应用上开发JSON编辑器功能&#xff0c;在引入组件后直接客户端跳转OK&#xff0c;但是在直接加载服务端渲染的时候一直报这…

【数据分析】Excel中的常用函数公式总结

目录 0 引用方式0.1 相对引用0.2 绝对引用0.3 混合引用0.4 3D引用0.5 命名引用 1 基础函数1.1 加法、减法、乘法和除法1.2 平均数1.3 求和1.4 最大值和最小值 2 文本函数2.1 合并单元格内容2.2 查找2.3 替换 3 逻辑函数3.1 IF函数3.2 AND和OR函数3.3 IFERROR函数 4 统计函数4.1…

Visual Studio使用Git忽略不想上传到远程仓库的文件

前言 作为一个.NET开发者而言&#xff0c;有着宇宙最强IDE&#xff1a;Visual Studio加持&#xff0c;让我们的开发效率得到了更好的提升。我们不需要担心环境变量的配置和其他代码管理工具&#xff0c;因为Visual Studio有着众多的拓展工具。废话不多说&#xff0c;直接进入正…