1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-08-01 16:28:03 +08:00

Compare commits

...

10 Commits

Author SHA1 Message Date
Guide
9cb8afd4bb
Merge pull request #2454 from fox-half-tian/main
修改 http/2.0 与 http/3.0 对比中的 安全性描述
2024-08-14 06:47:33 +08:00
FoxTian
685472f54c
Merge pull request #2 from fox-half-tian/修改-http/2.0-与-http/3.0-对比中的-安全性描述
Update other-network-questions.md
2024-08-13 22:34:28 +08:00
FoxTian
611c015aeb
Update other-network-questions.md
修改 http/2.0 与 http/3.0 对比中的 安全性描述
2024-08-13 22:33:59 +08:00
FoxTian
7bc7370d4b
Merge pull request #1 from Snailclimb/main
2024-08-13 22:30:56 +08:00
Guide
c0535df01c [docs update]完善HTTP/2.0 和 HTTP/3.0 的对比 2024-08-13 16:01:02 +08:00
Guide
43641a81f9
Merge pull request #2450 from liangkuai/main
[docs fix]修复拼写错误
2024-08-12 14:46:26 +08:00
凉快
c33993496c
[docs fix]修复拼写错误 2024-08-12 11:59:51 +08:00
Guide
af341e3b05 [docs update]完善回答HashMap 的长度为什么是 2 的幂次方 2024-08-11 15:33:02 +08:00
Guide
ee1e7a5140 Merge branch 'main' of github.com:Snailclimb/JavaGuide 2024-08-10 20:38:24 +08:00
Guide
e29ad07899 [docs update]内容完善 2024-08-10 20:38:10 +08:00
10 changed files with 158 additions and 55 deletions

View File

@ -211,14 +211,25 @@ HTTP/2.0 多路复用效果图(图源: [HTTP/2 For Web Developers](https://b
- **传输协议**HTTP/2.0 是基于 TCP 协议实现的HTTP/3.0 新增了 QUICQuick UDP Internet Connections 协议来实现可靠的传输,提供与 TLS/SSL 相当的安全性,具有较低的连接和传输延迟。你可以将 QUIC 看作是 UDP 的升级版本在其基础上新增了很多功能比如加密、重传等等。HTTP/3.0 之前名为 HTTP-over-QUIC从这个名字中我们也可以发现HTTP/3 最大的改造就是使用了 QUIC。 - **传输协议**HTTP/2.0 是基于 TCP 协议实现的HTTP/3.0 新增了 QUICQuick UDP Internet Connections 协议来实现可靠的传输,提供与 TLS/SSL 相当的安全性,具有较低的连接和传输延迟。你可以将 QUIC 看作是 UDP 的升级版本在其基础上新增了很多功能比如加密、重传等等。HTTP/3.0 之前名为 HTTP-over-QUIC从这个名字中我们也可以发现HTTP/3 最大的改造就是使用了 QUIC。
- **连接建立**HTTP/2.0 需要经过经典的 TCP 三次握手过程(由于安全的 HTTPS 连接建立还需要 TLS 握手,共需要大约 3 个 RTT。由于 QUIC 协议的特性TLS 1.3TLS 1.3 除了支持 1 个 RTT 的握手,还支持 0 个 RTT 的握手)连接建立仅需 0-RTT 或者 1-RTT。这意味着 QUIC 在最佳情况下不需要任何的额外往返时间就可以建立新连接。 - **连接建立**HTTP/2.0 需要经过经典的 TCP 三次握手过程(由于安全的 HTTPS 连接建立还需要 TLS 握手,共需要大约 3 个 RTT。由于 QUIC 协议的特性TLS 1.3TLS 1.3 除了支持 1 个 RTT 的握手,还支持 0 个 RTT 的握手)连接建立仅需 0-RTT 或者 1-RTT。这意味着 QUIC 在最佳情况下不需要任何的额外往返时间就可以建立新连接。
- **头部压缩**HTTP/2.0 使用 HPACK 算法进行头部压缩,而 HTTP/3.0 使用更高效的 QPACK 头压缩算法。
- **队头阻塞**HTTP/2.0 多请求复用一个 TCP 连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求。由于 QUIC 协议的特性HTTP/3.0 在一定程度上解决了队头阻塞Head-of-Line blocking, 简写HOL blocking问题一个连接建立多个不同的数据流这些数据流之间独立互不影响某个数据流发生丢包了其数据流不受影响本质上是多路复用+轮询)。 - **队头阻塞**HTTP/2.0 多请求复用一个 TCP 连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求。由于 QUIC 协议的特性HTTP/3.0 在一定程度上解决了队头阻塞Head-of-Line blocking, 简写HOL blocking问题一个连接建立多个不同的数据流这些数据流之间独立互不影响某个数据流发生丢包了其数据流不受影响本质上是多路复用+轮询)。
- **连接迁移**HTTP/3.0 支持连接迁移,因为 QUIC 使用 64 位 ID 标识连接,只要 ID 不变就不会中断,网络环境改变时(如从 Wi-Fi 切换到移动数据)也能保持连接。而 TCP 连接是由(源 IP源端口目的 IP目的端口组成这个四元组中一旦有一项值发生改变这个连接也就不能用了。
- **错误恢复**HTTP/3.0 具有更好的错误恢复机制,当出现丢包、延迟等网络问题时,可以更快地进行恢复和重传。而 HTTP/2.0 则需要依赖于 TCP 的错误恢复机制。 - **错误恢复**HTTP/3.0 具有更好的错误恢复机制,当出现丢包、延迟等网络问题时,可以更快地进行恢复和重传。而 HTTP/2.0 则需要依赖于 TCP 的错误恢复机制。
- **安全性**HTTP/2.0 和 HTTP/3.0 在安全性上都有较高的要求支持加密通信但在实现上有所不同。HTTP/2.0 使用 TLS 协议进行加密,而 HTTP/3.0 基于 QUIC 协议,包含了内置的加密和身份验证机制,可以提供更强的安全性。 - **安全性**在 HTTP/2.0 中TLS 用于加密和认证整个 HTTP 会话,包括所有的 HTTP 头部和数据负载。TLS的工作是在 TCP 层之上,它加密的是在 TCP 连接中传输的应用层的数据,并不会对 TCP 头部以及 TLS 记录层头部进行加密,所以在传输的过程中 TCP 头部可能会被攻击者篡改来干扰通信。而 HTTP/3.0 的 QUIC 对整个数据包(包括报文头和报文体)进行了加密与认证处理,保障安全性。
HTTP/1.0、HTTP/2.0 和 HTTP/3.0 的协议栈比较: HTTP/1.0、HTTP/2.0 和 HTTP/3.0 的协议栈比较:
![http-3-implementation](https://oss.javaguide.cn/github/javaguide/cs-basics/network/http-3-implementation.png) ![http-3-implementation](https://oss.javaguide.cn/github/javaguide/cs-basics/network/http-3-implementation.png)
下图是一个更详细的 HTTP/2.0 和 HTTP/3.0 对比图:
![HTTP/2.0 和 HTTP/3.0 详细对比图](https://oss.javaguide.cn/github/javaguide/cs-basics/network/http2-and-http3-stacks-comparison.png)
从上图可以看出:
- **HTTP/2.0**:使用 TCP 作为传输协议、使用 HPACK 进行头部压缩、依赖 TLS 进行加密。
- **HTTP/3.0**:使用基于 UDP 的 QUIC 协议、使用更高效的 QPACK 进行头部压缩、在 QUIC 中直接集成了 TLS。QUIC 协议具备连接迁移、拥塞控制与避免、流量控制等特性。
关于 HTTP/1.0 -> HTTP/3.0 更详细的演进介绍,推荐阅读[HTTP1 到 HTTP3 的工程优化](https://dbwu.tech/posts/http_evolution/)。 关于 HTTP/1.0 -> HTTP/3.0 更详细的演进介绍,推荐阅读[HTTP1 到 HTTP3 的工程优化](https://dbwu.tech/posts/http_evolution/)。
### HTTP 是不保存状态的协议, 如何保存用户状态? ### HTTP 是不保存状态的协议, 如何保存用户状态?

View File

@ -88,7 +88,7 @@ SELECT * FROM tb1 WHERE id < 500;
AVL 树是计算机科学中最早被发明的自平衡二叉查找树,它的名称来自于发明者 G.M. Adelson-Velsky 和 E.M. Landis 的名字缩写。AVL 树的特点是保证任何节点的左右子树高度之差不超过 1因此也被称为高度平衡二叉树它的查找、插入和删除在平均和最坏情况下的时间复杂度都是 O(logn)。 AVL 树是计算机科学中最早被发明的自平衡二叉查找树,它的名称来自于发明者 G.M. Adelson-Velsky 和 E.M. Landis 的名字缩写。AVL 树的特点是保证任何节点的左右子树高度之差不超过 1因此也被称为高度平衡二叉树它的查找、插入和删除在平均和最坏情况下的时间复杂度都是 O(logn)。
![AVL 树](https://oss.javaguide.cn/github/javaguide/cs-basics/data-structure/avl-tree.png) ![](https://oss.javaguide.cn/github/javaguide/cs-basics/data-structure/avl-tree.png)
AVL 树采用了旋转操作来保持平衡。主要有四种旋转操作LL 旋转、RR 旋转、LR 旋转和 RL 旋转。其中 LL 旋转和 RR 旋转分别用于处理左左和右右失衡,而 LR 旋转和 RL 旋转则用于处理左右和右左失衡。 AVL 树采用了旋转操作来保持平衡。主要有四种旋转操作LL 旋转、RR 旋转、LR 旋转和 RL 旋转。其中 LL 旋转和 RR 旋转分别用于处理左左和右右失衡,而 LR 旋转和 RL 旋转则用于处理左右和右左失衡。

View File

@ -341,15 +341,13 @@ InnoDB 使用缓冲池Buffer Pool缓存数据页和索引页MyISAM 使
### MyISAM 和 InnoDB 如何选择? ### MyISAM 和 InnoDB 如何选择?
大多数时候我们使用的都是 InnoDB 存储引擎,在某些读密集的情况下,使用 MyISAM 也是合适的。不过,前提是你的项目不介意 MyISAM 不支持事务、崩溃恢复等缺点(可是~我们一般都会介意啊)。 大多数时候我们使用的都是 InnoDB 存储引擎,在某些读密集的情况下,使用 MyISAM 也是合适的。不过,前提是你的项目不介意 MyISAM 不支持事务、崩溃恢复等缺点(可是~我们一般都会介意啊)。
《MySQL 高性能》上面有一句话这样写到: 《MySQL 高性能》上面有一句话这样写到:
> 不要轻易相信“MyISAM 比 InnoDB 快”之类的经验之谈这个结论往往不是绝对的。在很多我们已知场景中InnoDB 的速度都可以让 MyISAM 望尘莫及,尤其是用到了聚簇索引,或者需要访问的数据都可以放入内存的应用。 > 不要轻易相信“MyISAM 比 InnoDB 快”之类的经验之谈这个结论往往不是绝对的。在很多我们已知场景中InnoDB 的速度都可以让 MyISAM 望尘莫及,尤其是用到了聚簇索引,或者需要访问的数据都可以放入内存的应用。
一般情况下我们选择 InnoDB 都是没有问题的,但是某些情况下你并不在乎可扩展能力和并发能力,也不需要事务支持,也不在乎崩溃后的安全恢复问题的话,选择 MyISAM 也是一个不错的选择。但是一般情况下,我们都是需要考虑到这些问题的。 因此,对于咱们日常开发的业务系统来说,你几乎找不到什么理由使用 MyISAM 了,老老实实用默认的 InnoDB 就可以了!
因此,对于咱们日常开发的业务系统来说,你几乎找不到什么理由再使用 MyISAM 作为自己的 MySQL 数据库的存储引擎。
## MySQL 索引 ## MySQL 索引
@ -650,7 +648,7 @@ SELECT ... FOR UPDATE;
- **意向共享锁Intention Shared LockIS 锁)**事务有意向对表中的某些记录加共享锁S 锁),加共享锁前必须先取得该表的 IS 锁。 - **意向共享锁Intention Shared LockIS 锁)**事务有意向对表中的某些记录加共享锁S 锁),加共享锁前必须先取得该表的 IS 锁。
- **意向排他锁Intention Exclusive LockIX 锁)**事务有意向对表中的某些记录加排他锁X 锁),加排他锁之前必须先取得该表的 IX 锁。 - **意向排他锁Intention Exclusive LockIX 锁)**事务有意向对表中的某些记录加排他锁X 锁),加排他锁之前必须先取得该表的 IX 锁。
**意向锁是由数据引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享/排他锁之前InooDB 会先获取该数据行所在在数据表的对应意向锁。** **意向锁是由数据引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享/排他锁之前InnoDB 会先获取该数据行所在在数据表的对应意向锁。**
意向锁之间是互相兼容的。 意向锁之间是互相兼容的。

View File

@ -23,7 +23,7 @@ head:
1. **时间维度区分**:按照数据的创建时间、更新时间、过期时间等,将一定时间段内的数据视为热数据,超过该时间段的数据视为冷数据。例如,订单系统可以将 1 年前的订单数据作为冷数据1 年内的订单数据作为热数据。这种方法适用于数据的访问频率和时间有较强的相关性的场景。 1. **时间维度区分**:按照数据的创建时间、更新时间、过期时间等,将一定时间段内的数据视为热数据,超过该时间段的数据视为冷数据。例如,订单系统可以将 1 年前的订单数据作为冷数据1 年内的订单数据作为热数据。这种方法适用于数据的访问频率和时间有较强的相关性的场景。
2. **访问频率区分**:将高频访问的数据视为热数据,低频访问的数据视为冷数据。例如,内容系统可以将浏览量非常低的文章作为冷数据,浏览量较高的文章作为热数据。这种方法需要记录数据的访问频率,成本较高,适合访问频率和数据本身有较强的相关性的场景。 2. **访问频率区分**:将高频访问的数据视为热数据,低频访问的数据视为冷数据。例如,内容系统可以将浏览量非常低的文章作为冷数据,浏览量较高的文章作为热数据。这种方法需要记录数据的访问频率,成本较高,适合访问频率和数据本身有较强的相关性的场景。
几年前的数据并不一定都是数据,例如一些优质文章发表几年后依然有很多人访问,大部分普通用户新发表的文章却基本没什么人访问。 几年前的数据并不一定都是数据,例如一些优质文章发表几年后依然有很多人访问,大部分普通用户新发表的文章却基本没什么人访问。
这两种区分冷热数据的方法各有优劣,实际项目中,可以将两者结合使用。 这两种区分冷热数据的方法各有优劣,实际项目中,可以将两者结合使用。

View File

@ -305,8 +305,11 @@ public class ArrayList<E> extends AbstractList<E>
/** /**
* 以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。 * 以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。
* 返回的数组将是“安全的”,因为该列表不保留对它的引用。 (换句话说,这个方法必须分配一个新的数组)。 * 返回的数组将是“安全的”,因为该列表不保留对它的引用。
* 因此,调用者可以自由地修改返回的数组。 此方法充当基于阵列和基于集合的API之间的桥梁。 * (换句话说,这个方法必须分配一个新的数组)。
* 因此,调用者可以自由地修改返回的数组结构。
* 注意:如果元素是引用类型,修改元素的内容会影响到原列表中的对象。
* 此方法充当基于数组和基于集合的API之间的桥梁。
*/ */
public Object[] toArray() { public Object[] toArray() {
return Arrays.copyOf(elementData, size); return Arrays.copyOf(elementData, size);

View File

@ -185,7 +185,7 @@ final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
JDK1.8 之前 `HashMap` 底层是 **数组和链表** 结合在一起使用也就是 **链表散列**。HashMap 通过 key 的 `hashcode` 经过扰动函数处理过后得到 hash 值,然后通过 `(n - 1) & hash` 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。 JDK1.8 之前 `HashMap` 底层是 **数组和链表** 结合在一起使用也就是 **链表散列**。HashMap 通过 key 的 `hashcode` 经过扰动函数处理过后得到 hash 值,然后通过 `(n - 1) & hash` 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。
所谓扰动函数指的就是 HashMap 的 `hash` 方法。使用 `hash` 方法也就是扰动函数是为了防止一些实现比较差的 `hashCode()` 方法 换句话说使用扰动函数之后可以减少碰撞 `HashMap` 中的扰动函数(`hash` 方法)是用来优化哈希值的分布。通过对原始的 `hashCode()` 进行额外处理,扰动函数可以减小由于糟糕的 `hashCode()` 实现导致的碰撞,从而提高数据的分布均匀性
**JDK 1.8 HashMap 的 hash 方法源码:** **JDK 1.8 HashMap 的 hash 方法源码:**
@ -286,11 +286,55 @@ final void treeifyBin(Node<K,V>[] tab, int hash) {
### HashMap 的长度为什么是 2 的幂次方 ### HashMap 的长度为什么是 2 的幂次方
为了能让 HashMap 存取高效尽量较少碰撞也就是要尽量把数据分配均匀。我们上面也讲到了过了Hash 值的范围值-2147483648 到 2147483647前后加起来大概 40 亿的映射空间,只要哈希函数映射得比较均匀松散,一般应用是很难出现碰撞的。但问题是一个 40 亿长度的数组,内存是放不下的。所以这个散列值是不能直接拿来用的。用之前还要先做对数组的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标。 为了`HashMap` 存取高效并减少碰撞,我们需要确保数据尽量均匀分布。哈希值在 Java 中通常使用 `int` 表示,其范围是 `-2147483648 ~ 2147483647`前后加起来大概 40 亿的映射空间,只要哈希函数映射得比较均匀松散,一般应用是很难出现碰撞的。但是,问题是一个 40 亿长度的数组,内存是放不下的。所以这个散列值是不能直接拿来用的。用之前还要先做对数组的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标。
**这个算法应该如何设计呢?** **这个算法应该如何设计呢?**
我们首先可能会想到采用 % 取余的操作来实现。但是,重点来了:“**取余(%)操作中如果除数是 2 的幂次则等价于与其除数减一的与(&)操作**(也就是说 hash%length==hash&(length-1)的前提是 length 是 2 的 n 次方;)。” 并且 **采用二进制位操作 & 相对于 % 能够提高运算效率**,这就解释了 HashMap 的长度为什么是 2 的幂次方。 我们首先可能会想到采用 % 取余的操作来实现。但是,重点来了:“**取余(%)操作中如果除数是 2 的幂次则等价于与其除数减一的与(&)操作**(也就是说 `hash%length==hash&(length-1)` 的前提是 length 是 2 的 n 次方)。” 并且,**采用二进制位操作 & 相对于 % 能够提高运算效率**。
除了上面所说的位运算比取余效率高之外,我觉得更重要的一个原因是:**长度是 2 的幂次方,可以让 `HashMap` 在扩容的时候更均匀**。例如:
- length = 8 时length - 1 = 7 的二进制位`0111`
- length = 16 时length - 1 = 15 的二进制位`1111`
这时候原本存在 `HashMap` 中的元素计算新的数组位置时 `hash&(length-1)`,取决 hash 的第四个二进制位(从右数),会出现两种情况:
1. 第四个二进制位为 0数组位置不变也就是说当前元素在新数组和旧数组的位置相同。
2. 第四个二进制位为 1数组位置在新数组扩容之后的那一部分。
这里列举一个例子:
```plain
假设有一个元素的哈希值为 10101100
旧数组元素位置计算:
hash = 10101100
length - 1 = 00000111
& -----------------
index = 00000100 (4)
新数组元素位置计算:
hash = 10101100
length - 1 = 00001111
& -----------------
index = 00001100 (12)
看第四位(从右数):
1.高位为 0位置不变。
2.高位为 1移动到新位置原索引位置+原容量)。
```
⚠️注意:这里列举的场景看的是第四个二进制位,更准确点来说看的是高位(从右数),例如 `length = 32` 时,`length - 1 = 31`,二进制为 `11111`,这里看的就是第五个二进制位。
也就是说扩容之后,在旧数组元素 hash 值比较均匀(至于 hash 值均不均匀,取决于前面讲的对象的 `hashcode()` 方法和扰动函数)的情况下,新数组元素也会被分配的比较均匀,最好的情况是会有一半在新数组的前半部分,一半在新数组后半部分。
这样也使得扩容机制变得简单和高效,扩容后只需检查哈希值高位的变化来决定元素的新位置,要么位置不变(高位为 0要么就是移动到新位置高位为 1原索引位置+原容量)。
最后,简单总结一下 `HashMap` 的长度是 2 的幂次方的原因:
1. 位运算效率更高:位运算(&)比取余运算(%)更高效。当长度为 2 的幂次方时,`hash % length` 等价于 `hash & (length - 1)`
2. 可以更好地保证哈希值的均匀分布:扩容之后,在旧数组元素 hash 值比较均匀的情况下,新数组元素也会被分配的比较均匀,最好的情况是会有一半在新数组的前半部分,一半在新数组后半部分。
3. 扩容机制变得简单和高效:扩容后只需检查哈希值高位的变化来决定元素的新位置,要么位置不变(高位为 0要么就是移动到新位置高位为 1原索引位置+原容量)。
### HashMap 多线程操作导致死循环问题 ### HashMap 多线程操作导致死循环问题

View File

@ -125,9 +125,8 @@ icon: "xitongsheji"
- [Quartz](https://github.com/quartz-scheduler/quartz)一个很火的开源任务调度框架Java 定时任务领域的老大哥或者说参考标准, 很多其他任务调度框架都是基于 `quartz` 开发的,比如当当网的`elastic-job`就是基于`quartz`二次开发之后的分布式调度解决方案 - [Quartz](https://github.com/quartz-scheduler/quartz)一个很火的开源任务调度框架Java 定时任务领域的老大哥或者说参考标准, 很多其他任务调度框架都是基于 `quartz` 开发的,比如当当网的`elastic-job`就是基于`quartz`二次开发之后的分布式调度解决方案
- [XXL-JOB](https://github.com/xuxueli/xxl-job) :XXL-JOB 是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 - [XXL-JOB](https://github.com/xuxueli/xxl-job) :XXL-JOB 是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
- [Elastic-Job](http://elasticjob.io/index_zh.html)Elastic-Job 是当当网开源的一个基于 Quartz 和 Zookeeper 的分布式调度解决方案,由两个相互独立的子项目 Elastic-Job-Lite 和 Elastic-Job-Cloud 组成,一般我们只要使用 Elastic-Job-Lite 就好。 - [Elastic-Job](http://elasticjob.io/index_zh.html)Elastic-Job 是当当网开源的一个基于 Quartz 和 Zookeeper 的分布式调度解决方案,由两个相互独立的子项目 Elastic-Job-Lite 和 Elastic-Job-Cloud 组成,一般我们只要使用 Elastic-Job-Lite 就好。
- [EasyScheduler](https://github.com/analysys/EasyScheduler "EasyScheduler") (已经更名为 DolphinScheduler已经成为 Apache 孵化器项目):Easy Scheduler 是一个分布式工作流任务调度系统,主要解决“复杂任务依赖但无法直接监控任务健康状态”的问题。Easy Scheduler 以 DAG 方式组装任务,可以实时监控任务的运行状态。同时,它支持重试,重新运行等操作... 。 - [EasyScheduler](https://github.com/analysys/EasyScheduler "EasyScheduler") (已经更名为 DolphinScheduler已经成为 Apache 孵化器项目):分布式易扩展的可视化工作流任务调度平台,主要解决“复杂任务依赖但无法直接监控任务健康状态”的问题。
- [PowerJob](https://gitee.com/KFCFans/PowerJob):新一代分布式任务调度与计算框架,支持 CRON、API、固定频率、固定延迟等调度策略提供工作流来编排任务解决依赖关系使用简单功能强大文档齐全欢迎各位接入使用<http://www.powerjob.tech/> - [PowerJob](https://gitee.com/KFCFans/PowerJob):新一代分布式任务调度与计算框架,支持 CRON、API、固定频率、固定延迟等调度策略提供工作流来编排任务解决依赖关系使用简单功能强大文档齐全欢迎各位接入使用<http://www.powerjob.tech/>
- [DolphinScheduler](https://github.com/apache/dolphinscheduler):分布式易扩展的可视化工作流任务调度平台。
## 分布式 ## 分布式

View File

@ -18,7 +18,7 @@ footer: |-
## 关于网站 ## 关于网站
JavaGuide 已经持续维护 5 年多了,累计提交了 **5000+** commit ,共有 **440** 多位朋友参与维护。真心希望能够把这个项目做好,真正能够帮助到有需要的朋友! JavaGuide 已经持续维护 6 年多了,累计提交了 **5500+** commit ,共有 **520+** 多位贡献者共同参与维护和完善。真心希望能够把这个项目做好,真正能够帮助到有需要的朋友!
如果觉得 JavaGuide 的内容对你有帮助的话,还请点个免费的 Star绝不强制点 Star觉得内容不错有收货再点赞就好这是对我最大的鼓励感谢各位一路同行共勉传送门[GitHub](https://github.com/Snailclimb/JavaGuide) | [Gitee](https://gitee.com/SnailClimb/JavaGuide)。 如果觉得 JavaGuide 的内容对你有帮助的话,还请点个免费的 Star绝不强制点 Star觉得内容不错有收货再点赞就好这是对我最大的鼓励感谢各位一路同行共勉传送门[GitHub](https://github.com/Snailclimb/JavaGuide) | [Gitee](https://gitee.com/SnailClimb/JavaGuide)。

View File

@ -94,7 +94,7 @@ AOP 之所以叫面向切面编程,是因为它的核心思想就是将横切
- **连接点JoinPoint**:连接点是方法调用或者方法执行时的某个特定时刻(如方法调用、异常抛出等)。 - **连接点JoinPoint**:连接点是方法调用或者方法执行时的某个特定时刻(如方法调用、异常抛出等)。
- **通知Advice**通知就是切面在某个连接点要执行的操作。通知有五种类型分别是前置通知Before、后置通知After、返回通知AfterReturning、异常通知AfterThrowing和环绕通知Around。前四种通知都是在目标方法的前后执行而环绕通知可以控制目标方法的执行过程。 - **通知Advice**通知就是切面在某个连接点要执行的操作。通知有五种类型分别是前置通知Before、后置通知After、返回通知AfterReturning、异常通知AfterThrowing和环绕通知Around。前四种通知都是在目标方法的前后执行而环绕通知可以控制目标方法的执行过程。
- **切点Pointcut**:一个切点是一个表达式,它用来匹配哪些连接点需要被切面所增强。切点可以通过注解、正则表达式、逻辑运算等方式来定义。比如 `execution(* com.xyz.service..*(..))`匹配 `com.xyz.service` 包及其子包下的类或接口。 - **切点Pointcut**:一个切点是一个表达式,它用来匹配哪些连接点需要被切面所增强。切点可以通过注解、正则表达式、逻辑运算等方式来定义。比如 `execution(* com.xyz.service..*(..))`匹配 `com.xyz.service` 包及其子包下的类或接口。
- **织入Weaving**织入是将切面和目标对象连接起来的过程也就是将通知应用到切点匹配的连接点上。常见的织入时机有两种分别是编译期织入AspectJ和运行期织入AspectJ - **织入Weaving**:织入是将切面和目标对象连接起来的过程,也就是将通知应用到切点匹配的连接点上。常见的织入时机有两种,分别是编译期织入(Compile-Time Weaving 如:AspectJ和运行期织入Runtime Weaving 如:AspectJ、Spring AOP)。
### AOP 解决了什么问题? ### AOP 解决了什么问题?

View File

@ -368,38 +368,43 @@ FastJSON 实现数据脱敏的方式主要有两种:
- 基于注解 `@JSONField` 实现:需要自定义一个用于脱敏的序列化的类,然后在需要脱敏的字段上通过 `@JSONField` 中的 `serializeUsing` 指定为我们自定义的序列化类型即可。 - 基于注解 `@JSONField` 实现:需要自定义一个用于脱敏的序列化的类,然后在需要脱敏的字段上通过 `@JSONField` 中的 `serializeUsing` 指定为我们自定义的序列化类型即可。
- 基于序列化过滤器:需要实现 `ValueFilter` 接口,重写 `process` 方法完成自定义脱敏,然后在 JSON 转换时使用自定义的转换策略。具体实现可参考这篇文章: <https://juejin.cn/post/7067916686141161479> - 基于序列化过滤器:需要实现 `ValueFilter` 接口,重写 `process` 方法完成自定义脱敏,然后在 JSON 转换时使用自定义的转换策略。具体实现可参考这篇文章: <https://juejin.cn/post/7067916686141161479>
### Mybatis-mate ### Mybatis-Mate
MybatisPlus 也提供了数据脱敏模块 mybatis-mate。mybatis-mate 为 MybatisPlus 企业级模块,使用之前需要配置授权码(付费),旨在更敏捷优雅处理数据。 先介绍一下 MyBatis、MyBatis-Plus 和 Mybatis-Mate 这三者的关系:
配置内容如下所示: - MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。
- MyBatis-Plus 是一个 MyBatis 的增强工具,能够极大地简化持久层的开发工作。
- Mybatis-Mate 是为 MyBatis-Plus 提供的企业级模块,旨在更敏捷优雅处理数据。不过,使用之前需要配置授权码(付费)。
```yaml Mybatis-Mate 支持敏感词脱敏,内置手机号、邮箱、银行卡号等 9 种常用脱敏规则。
# Mybatis Mate 配置
mybatis-mate: ```java
cert: @FieldSensitive("testStrategy")
grant: jxftsdfggggx private String username;
license: GKXP9r4MCJhGID/DTGigcBcLmZjb1YZGjE4GXaAoxbtGsPC20sxpEtiUr2F7Nb1ANTUekvF6Syo6DzraA4M4oacwoLVTglzfvaEfadfsd232485eLJK1QsskrSJmreMnEaNh9lsV7Lpbxy9JeGCeM0HPEbRvq8Y+8dUt5bQYLklsa3ZIBexir+4XykZY15uqn1pYIp4pEK0+aINTa57xjJNoWuBIqm7BdFIb4l1TAcPYMTsMXhF5hfMmKD2h391HxWTshJ6jbt4YqdKD167AgeoM+B+DE1jxlLjcpskY+kFs9piOS7RCcmKBBUOgX2BD/JxhR2gQ==
@Configuration
public class SensitiveStrategyConfig {
/**
* 注入脱敏策略
*/
@Bean
public ISensitiveStrategy sensitiveStrategy() {
// 自定义 testStrategy 类型脱敏处理
return new SensitiveStrategy().addStrategy("testStrategy", t -> t + "***test***");
}
}
// 跳过脱密处理,用于编辑场景
RequestDataTransfer.skipSensitive();
``` ```
具体实现可参考 baomidou 提供的如下代码:<https://gitee.com/baomidou/mybatis-mate-examples>
### MyBatis-Flex ### MyBatis-Flex
类似于 MybatisPlusMyBatis-Flex 也是一个 MyBatis 增强框架。MyBatis-Flex 同样提供了数据脱敏功能,并且是可以免费使用的。 类似于 MybatisPlusMyBatis-Flex 也是一个 MyBatis 增强框架。MyBatis-Flex 同样提供了数据脱敏功能,并且是可以免费使用的。
MyBatis-Flex 提供了 `@ColumnMask()` 注解,以及内置的 9 种脱敏规则,开箱即用: MyBatis-Flex 提供了 `@ColumnMask()` 注解,以及内置的 9 种脱敏规则,开箱即用:
- 用户名脱敏
- 手机号脱敏
- 固定电话脱敏
- 身份证号脱敏
- 车牌号脱敏
- 地址脱敏
- 邮件脱敏
- 密码脱敏
- 银行卡号脱敏
```java ```java
/** /**
* 内置的数据脱敏方式 * 内置的数据脱敏方式
@ -465,14 +470,57 @@ public class Account {
如果这些内置的脱敏规则不满足你的要求的话,你还可以自定义脱敏规则。 如果这些内置的脱敏规则不满足你的要求的话,你还可以自定义脱敏规则。
1、通过 `MaskManager` 注册新的脱敏规则:
```java
MaskManager.registerMaskProcessor("自定义规则名称"
, data -> {
return data;
})
```
2、使用自定义的脱敏规则
```java
@Table("tb_account")
public class Account {
@Id(keyType = KeyType.Auto)
private Long id;
@ColumnMask("自定义规则名称")
private String userName;
}
```
并且对于需要跳过脱密处理的场景例如进入编辑页面编辑用户数据MyBatis-Flex 也提供了对应的支持:
1. **`MaskManager#execWithoutMask`**(推荐):该方法使用了模版方法设计模式,保障跳过脱敏处理并执行相关逻辑后自动恢复脱敏处理。
2. **`MaskManager#skipMask`**:跳过脱敏处理。
3. **`MaskManager#restoreMask`**:恢复脱敏处理,确保后续的操作继续使用脱敏逻辑。
`MaskManager#execWithoutMask`方法实现如下:
```java
public static <T> T execWithoutMask(Supplier<T> supplier) {
try {
skipMask();
return supplier.get();
} finally {
restoreMask();
}
}
```
`MaskManager``skipMask``restoreMask`方法一般配套使用,推荐`try{...}finally{...}`模式。
## 总结 ## 总结
本文主要介绍了数据脱敏的相关内容,首先介绍了数据脱敏的概念,在此基础上介绍了常用的数据脱敏规则;随后介绍了本文的重点 Hutool 工具及其使用方法,在此基础上进行了实操,分别演示了使用 DesensitizedUtil 工具类、配合 Jackson 通过注解的方式完成数据脱敏;最后,介绍了一些常见的数据脱敏方法,并附上了对应的教程链接供大家参考,本文内容如有不当之处,还请大家批评指正。 这篇文章主要介绍了:
## 推荐阅读 - 数据脱敏的定义:数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。
- 常用的脱敏规则:替换、删除、重排、加噪和加密。
- [Spring Boot 日志、配置文件、接口数据如何脱敏?老鸟们都是这样玩的!](https://mp.weixin.qq.com/s/59osrnjyPJ7BV070x6ABwQ) - 常用的脱敏工具Hutool、Apache ShardingSphere、FastJSON、Mybatis-Mate 和 MyBatis-Flex。
- [大厂也在用的 6 种数据脱敏方案,严防泄露数据的“内鬼”](https://mp.weixin.qq.com/s/_Dgekk1AJsIx0TTlnH6kUA)
## 参考 ## 参考