mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-08-14 05:21:42 +08:00
Compare commits
9 Commits
15e3bd3124
...
8dba9eb7c0
Author | SHA1 | Date | |
---|---|---|---|
|
8dba9eb7c0 | ||
|
5f828a0060 | ||
|
d2bb3052df | ||
|
0ac9baa344 | ||
|
7628b6178d | ||
|
3a306606e9 | ||
|
386cfe7592 | ||
|
e78f45c9f1 | ||
|
9752436602 |
@ -103,18 +103,22 @@ star: 2
|
|||||||
|
|
||||||
## 如何加入?
|
## 如何加入?
|
||||||
|
|
||||||
两年前,星球的定价是 **50/年** ,这是星球的最低定价,我还附送了 33 元优惠券。扣除了星球手续费,发了各种福利之后,几乎就是纯粹做公益。感兴趣的小伙伴可以看看我在 2020-01-03 发的头条:[做了一个很久没敢做的事情](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247486049&idx=1&sn=e0161b409e8f164251bdaa0c83a476bc&chksm=cea245aaf9d5ccbcafdb95a546d959508814085620aabdbb4385c4b8cea6e50bf157c3697041&token=1614894361&lang=zh_CN#rd),去考古一下。
|
两年前,星球的定价是 **50/年** ,这是星球的最低定价,我还附送了 33 元优惠券。扣除了星球手续费,发了各种福利之后,几乎就是纯粹做公益。
|
||||||
|
|
||||||
随着时间推移,星球积累的干货资源越来越多,我花在星球上的时间也越来越多。于是,星球的定价慢慢被调整为了 **159/年** (**续费半价**)!
|
感兴趣的小伙伴可以看看我在 2020-01-03 发的头条:[做了一个很久没敢做的事情](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247486049&idx=1&sn=e0161b409e8f164251bdaa0c83a476bc&chksm=cea245aaf9d5ccbcafdb95a546d959508814085620aabdbb4385c4b8cea6e50bf157c3697041&token=1614894361&lang=zh_CN#rd),去考古一下。
|
||||||
|
|
||||||
目前已经有 **1.3w+** 人加入星球,随着加入的人数增加,这个定价还会继续调整,越早加入越划算!
|

|
||||||
|
|
||||||
为了感谢大家的支持,我这里再送出一张新人优惠券,使用优惠券 **139/年** 加入(数量有限,即将调整为 **199/年**)。
|
随着时间推移,星球积累的干货资源越来越多,我花在星球上的时间也越来越多。于是,我将星球的定价慢慢调整为了 **159/年**!后续会将星球的价格调整为 **199/年**,想要加入的小伙伴一定要尽早。
|
||||||
|
|
||||||
|
你可以添加我的微信(没有手机号再申请微信,故使用企业微信。不过,请放心,这个号的消息也是我本人处理,平时最常看这个微信)领取星球专属优惠券,限时 **130/年** 加入(续费半价)!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
或者你也可以直接使用下面这张 **20** 元的优惠券,**139/年** 加入。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
如果你在犹豫要不要加入的话,我建议你进来体验一下,三天之内知识星球 APP 右上角可以申请全额退款,秒到账!绝对不会坑大家!
|
|
||||||
|
|
||||||
进入星球之后,你可以为自己制定一个目标,比如自己想要进入某某还不错的公司或者达成什么成就(一定要是还算有点挑战的目标)。待你完成目标在星球分享之后,我会将星球的门票费退还给你。
|
进入星球之后,你可以为自己制定一个目标,比如自己想要进入某某还不错的公司或者达成什么成就(一定要是还算有点挑战的目标)。待你完成目标在星球分享之后,我会将星球的门票费退还给你。
|
||||||
|
|
||||||
**真诚欢迎准备面试的小伙伴加入星球一起交流!真心希望能够帮助到更多小伙伴!**
|
**真诚欢迎准备面试的小伙伴加入星球一起交流!真心希望能够帮助到更多小伙伴!**
|
||||||
|
@ -76,7 +76,7 @@ MySQL 没有命中缓存,那么就会进入分析器,分析器主要是用
|
|||||||
|
|
||||||
### 2.1 查询语句
|
### 2.1 查询语句
|
||||||
|
|
||||||
说了以上这么多,那么究竟一条 SQL 语句是如何执行的呢?其实我们的 SQL 可以分为两种,一种是查询,一种是更新(增加,更新,删除)。我们先分析下查询语句,语句如下:
|
说了以上这么多,那么究竟一条 SQL 语句是如何执行的呢?其实我们的 SQL 可以分为两种,一种是查询,一种是更新(增加,修改,删除)。我们先分析下查询语句,语句如下:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
select * from tb_student A where A.age='18' and A.name=' 张三 ';
|
select * from tb_student A where A.age='18' and A.name=' 张三 ';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 缓存基础常见面试题总结
|
title: 缓存基础常见面试题总结(付费)
|
||||||
category: 数据库
|
category: 数据库
|
||||||
tag:
|
tag:
|
||||||
- Redis
|
- Redis
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: Redis 集群详解
|
title: Redis 集群详解(付费)
|
||||||
category: 数据库
|
category: 数据库
|
||||||
tag:
|
tag:
|
||||||
- Redis
|
- Redis
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 分布式事务
|
title: 分布式事务(付费)
|
||||||
category: 分布式
|
category: 分布式
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 降级&熔断
|
title: 降级&熔断(付费)
|
||||||
category: 高可用
|
category: 高可用
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 优质面经
|
title: 优质面经(付费)
|
||||||
category: 知识星球
|
category: 知识星球
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 常见面试题自测
|
title: 常见面试题自测(付费)
|
||||||
category: 知识星球
|
category: 知识星球
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 手把手教你如何准备面试
|
title: 手把手教你如何准备面试(付费)
|
||||||
category: 知识星球
|
category: 知识星球
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ tag:
|
|||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
## 1. ArrayList 简介
|
## ArrayList 简介
|
||||||
|
|
||||||
`ArrayList` 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用`ensureCapacity`操作来增加 `ArrayList` 实例的容量。这可以减少递增式再分配的数量。
|
`ArrayList` 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用`ensureCapacity`操作来增加 `ArrayList` 实例的容量。这可以减少递增式再分配的数量。
|
||||||
|
|
||||||
@ -24,12 +24,12 @@ public class ArrayList<E> extends AbstractList<E>
|
|||||||
- `ArrayList` 实现了 **`Cloneable` 接口** ,即覆盖了函数`clone()`,能被克隆。
|
- `ArrayList` 实现了 **`Cloneable` 接口** ,即覆盖了函数`clone()`,能被克隆。
|
||||||
- `ArrayList` 实现了 `java.io.Serializable`接口,这意味着`ArrayList`支持序列化,能通过序列化去传输。
|
- `ArrayList` 实现了 `java.io.Serializable`接口,这意味着`ArrayList`支持序列化,能通过序列化去传输。
|
||||||
|
|
||||||
### 1.1. Arraylist 和 Vector 的区别?
|
### Arraylist 和 Vector 的区别?
|
||||||
|
|
||||||
1. `ArrayList` 是 `List` 的主要实现类,底层使用 `Object[ ]`存储,适用于频繁的查找工作,线程不安全 ;
|
1. `ArrayList` 是 `List` 的主要实现类,底层使用 `Object[ ]`存储,适用于频繁的查找工作,线程不安全 ;
|
||||||
2. `Vector` 是 `List` 的古老实现类,底层使用 `Object[ ]`存储,线程安全的。
|
2. `Vector` 是 `List` 的古老实现类,底层使用 `Object[ ]`存储,线程安全的。
|
||||||
|
|
||||||
### 1.2. Arraylist 与 LinkedList 区别?
|
### Arraylist 与 LinkedList 区别?
|
||||||
|
|
||||||
1. **是否保证线程安全:** `ArrayList` 和 `LinkedList` 都是不同步的,也就是不保证线程安全;
|
1. **是否保证线程安全:** `ArrayList` 和 `LinkedList` 都是不同步的,也就是不保证线程安全;
|
||||||
2. **底层数据结构:** `Arraylist` 底层使用的是 **`Object` 数组**;`LinkedList` 底层使用的是 **双向链表** 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
|
2. **底层数据结构:** `Arraylist` 底层使用的是 **`Object` 数组**;`LinkedList` 底层使用的是 **双向链表** 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
|
||||||
@ -37,7 +37,7 @@ public class ArrayList<E> extends AbstractList<E>
|
|||||||
4. **是否支持快速随机访问:** `LinkedList` 不支持高效的随机元素访问,而 `ArrayList` 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于`get(int index)`方法)。
|
4. **是否支持快速随机访问:** `LinkedList` 不支持高效的随机元素访问,而 `ArrayList` 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于`get(int index)`方法)。
|
||||||
5. **内存空间占用:** `ArrayList` 的空 间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 `LinkedList` 的空间花费则体现在它的每一个元素都需要消耗比 `ArrayList` 更多的空间(因为要存放直接后继和直接前驱以及数据)。
|
5. **内存空间占用:** `ArrayList` 的空 间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 `LinkedList` 的空间花费则体现在它的每一个元素都需要消耗比 `ArrayList` 更多的空间(因为要存放直接后继和直接前驱以及数据)。
|
||||||
|
|
||||||
## 2. ArrayList 核心源码解读
|
## ArrayList 核心源码解读
|
||||||
|
|
||||||
```java
|
```java
|
||||||
package java.util;
|
package java.util;
|
||||||
@ -546,9 +546,9 @@ public class ArrayList<E> extends AbstractList<E>
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3. ArrayList 扩容机制分析
|
## ArrayList 扩容机制分析
|
||||||
|
|
||||||
### 3.1. 先从 ArrayList 的构造函数说起
|
### 先从 ArrayList 的构造函数说起
|
||||||
|
|
||||||
**(JDK8)ArrayList 有三种方式来初始化,构造方法源码如下:**
|
**(JDK8)ArrayList 有三种方式来初始化,构造方法源码如下:**
|
||||||
|
|
||||||
@ -603,15 +603,15 @@ public class ArrayList<E> extends AbstractList<E>
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
细心的同学一定会发现 :**以无参数构造方法创建 `ArrayList` 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为 10。** 下面在我们分析 ArrayList 扩容时会讲到这一点内容!
|
细心的同学一定会发现 :**以无参数构造方法创建 ``ArrayList`` 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为 10。** 下面在我们分析 ArrayList 扩容时会讲到这一点内容!
|
||||||
|
|
||||||
> 补充:JDK6 new 无参构造的 `ArrayList` 对象时,直接创建了长度是 10 的 `Object[]` 数组 elementData 。
|
> 补充:JDK6 new 无参构造的 `ArrayList` 对象时,直接创建了长度是 10 的 `Object[]` 数组 elementData 。
|
||||||
|
|
||||||
### 3.2. 一步一步分析 ArrayList 扩容机制
|
### 一步一步分析 ArrayList 扩容机制
|
||||||
|
|
||||||
这里以无参构造函数创建的 ArrayList 为例分析
|
这里以无参构造函数创建的 ArrayList 为例分析
|
||||||
|
|
||||||
#### 3.2.1. 先来看 `add` 方法
|
#### 先来看 `add` 方法
|
||||||
|
|
||||||
```java
|
```java
|
||||||
/**
|
/**
|
||||||
@ -628,7 +628,7 @@ public class ArrayList<E> extends AbstractList<E>
|
|||||||
|
|
||||||
> **注意** :JDK11 移除了 `ensureCapacityInternal()` 和 `ensureExplicitCapacity()` 方法
|
> **注意** :JDK11 移除了 `ensureCapacityInternal()` 和 `ensureExplicitCapacity()` 方法
|
||||||
|
|
||||||
#### 3.2.2. 再来看看 `ensureCapacityInternal()` 方法
|
#### 再来看看 `ensureCapacityInternal()` 方法
|
||||||
|
|
||||||
(JDK7)可以看到 `add` 方法 首先调用了`ensureCapacityInternal(size + 1)`
|
(JDK7)可以看到 `add` 方法 首先调用了`ensureCapacityInternal(size + 1)`
|
||||||
|
|
||||||
@ -648,7 +648,7 @@ public class ArrayList<E> extends AbstractList<E>
|
|||||||
|
|
||||||
> 此处和后续 JDK8 代码格式化略有不同,核心代码基本一样。
|
> 此处和后续 JDK8 代码格式化略有不同,核心代码基本一样。
|
||||||
|
|
||||||
#### 3.2.3. `ensureExplicitCapacity()` 方法
|
#### `ensureExplicitCapacity()` 方法
|
||||||
|
|
||||||
如果调用 `ensureCapacityInternal()` 方法就一定会进入(执行)这个方法,下面我们来研究一下这个方法的源码!
|
如果调用 `ensureCapacityInternal()` 方法就一定会进入(执行)这个方法,下面我们来研究一下这个方法的源码!
|
||||||
|
|
||||||
@ -673,7 +673,7 @@ public class ArrayList<E> extends AbstractList<E>
|
|||||||
|
|
||||||
直到添加第 11 个元素,minCapacity(为 11)比 elementData.length(为 10)要大。进入 grow 方法进行扩容。
|
直到添加第 11 个元素,minCapacity(为 11)比 elementData.length(为 10)要大。进入 grow 方法进行扩容。
|
||||||
|
|
||||||
#### 3.2.4. `grow()` 方法
|
#### `grow()` 方法
|
||||||
|
|
||||||
```java
|
```java
|
||||||
/**
|
/**
|
||||||
@ -718,7 +718,7 @@ public class ArrayList<E> extends AbstractList<E>
|
|||||||
- java 中的 `length()` 方法是针对字符串说的,如果想看这个字符串的长度则用到 `length()` 这个方法.
|
- java 中的 `length()` 方法是针对字符串说的,如果想看这个字符串的长度则用到 `length()` 这个方法.
|
||||||
- java 中的 `size()` 方法是针对泛型集合说的,如果想看这个泛型有多少个元素,就调用此方法来查看!
|
- java 中的 `size()` 方法是针对泛型集合说的,如果想看这个泛型有多少个元素,就调用此方法来查看!
|
||||||
|
|
||||||
#### 3.2.5. `hugeCapacity()` 方法。
|
#### `hugeCapacity()` 方法。
|
||||||
|
|
||||||
从上面 `grow()` 方法源码我们知道: 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) `hugeCapacity()` 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,如果 minCapacity 大于最大容量,则新容量则为`Integer.MAX_VALUE`,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 `Integer.MAX_VALUE - 8`。
|
从上面 `grow()` 方法源码我们知道: 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) `hugeCapacity()` 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,如果 minCapacity 大于最大容量,则新容量则为`Integer.MAX_VALUE`,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 `Integer.MAX_VALUE - 8`。
|
||||||
|
|
||||||
@ -736,11 +736,11 @@ public class ArrayList<E> extends AbstractList<E>
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.3. `System.arraycopy()` 和 `Arrays.copyOf()`方法
|
### `System.arraycopy()` 和 `Arrays.copyOf()`方法
|
||||||
|
|
||||||
阅读源码的话,我们就会发现 ArrayList 中大量调用了这两个方法。比如:我们上面讲的扩容操作以及`add(int index, E element)`、`toArray()` 等方法中都用到了该方法!
|
阅读源码的话,我们就会发现 ArrayList 中大量调用了这两个方法。比如:我们上面讲的扩容操作以及`add(int index, E element)`、`toArray()` 等方法中都用到了该方法!
|
||||||
|
|
||||||
#### 3.3.1. `System.arraycopy()` 方法
|
#### `System.arraycopy()` 方法
|
||||||
|
|
||||||
源码:
|
源码:
|
||||||
|
|
||||||
@ -807,7 +807,7 @@ public class ArraycopyTest {
|
|||||||
0 1 99 2 3 0 0 0 0 0
|
0 1 99 2 3 0 0 0 0 0
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 3.3.2. `Arrays.copyOf()`方法
|
#### `Arrays.copyOf()`方法
|
||||||
|
|
||||||
源码:
|
源码:
|
||||||
|
|
||||||
@ -856,7 +856,7 @@ public class ArrayscopyOfTest {
|
|||||||
10
|
10
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 3.3.3. 两者联系和区别
|
#### 两者联系和区别
|
||||||
|
|
||||||
**联系:**
|
**联系:**
|
||||||
|
|
||||||
@ -866,9 +866,9 @@ public class ArrayscopyOfTest {
|
|||||||
|
|
||||||
`arraycopy()` 需要目标数组,将原数组拷贝到你自己定义的数组里或者原数组,而且可以选择拷贝的起点和长度以及放入新数组中的位置 `copyOf()` 是系统自动在内部新建一个数组,并返回该数组。
|
`arraycopy()` 需要目标数组,将原数组拷贝到你自己定义的数组里或者原数组,而且可以选择拷贝的起点和长度以及放入新数组中的位置 `copyOf()` 是系统自动在内部新建一个数组,并返回该数组。
|
||||||
|
|
||||||
### 3.4. `ensureCapacity`方法
|
### `ensureCapacity`方法
|
||||||
|
|
||||||
ArrayList 源码中有一个 `ensureCapacity` 方法不知道大家注意到没有,这个方法 ArrayList 内部没有被调用过,所以很显然是提供给用户调用的,那么这个方法有什么作用呢?
|
`ArrayList` 源码中有一个 `ensureCapacity` 方法不知道大家注意到没有,这个方法 `ArrayList` 内部没有被调用过,所以很显然是提供给用户调用的,那么这个方法有什么作用呢?
|
||||||
|
|
||||||
```java
|
```java
|
||||||
/**
|
/**
|
||||||
@ -891,7 +891,7 @@ ArrayList 源码中有一个 `ensureCapacity` 方法不知道大家注意到没
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**最好在 add 大量元素之前用 `ensureCapacity` 方法,以减少增量重新分配的次数**
|
理论上来说,最好在向 `ArrayList` 添加大量元素之前用 `ensureCapacity` 方法,以减少增量重新分配的次数
|
||||||
|
|
||||||
我们通过下面的代码实际测试以下这个方法的效果:
|
我们通过下面的代码实际测试以下这个方法的效果:
|
||||||
|
|
||||||
@ -939,4 +939,7 @@ public class EnsureCapacityTest {
|
|||||||
使用ensureCapacity方法后:1773
|
使用ensureCapacity方法后:1773
|
||||||
```
|
```
|
||||||
|
|
||||||
通过运行结果,我们可以看出向 ArrayList 添加大量元素之前最好先使用`ensureCapacity` 方法,以减少增量重新分配的次数。
|
通过运行结果,我们可以看出向 `ArrayList` 添加大量元素之前使用`ensureCapacity` 方法可以提升性能。不过,这个性能差距几乎可以忽略不计。而且,实际项目根本也不可能往 `ArrayList` 里面添加这么多元素。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种
|
|||||||
|
|
||||||
由上图可以看出:线程创建之后它将处于 **NEW(新建)** 状态,调用 `start()` 方法后开始运行,线程这时候处于 **READY(可运行)** 状态。可运行状态的线程获得了 CPU 时间片(timeslice)后就处于 **RUNNING(运行)** 状态。
|
由上图可以看出:线程创建之后它将处于 **NEW(新建)** 状态,调用 `start()` 方法后开始运行,线程这时候处于 **READY(可运行)** 状态。可运行状态的线程获得了 CPU 时间片(timeslice)后就处于 **RUNNING(运行)** 状态。
|
||||||
|
|
||||||
> 在操作系统中层面线程有 READY 和 RUNNING 状态,而在 JVM 层面只能看到 RUNNABLE 状态(图源:[HowToDoInJava](https://howtodoinJava.com/ "HowToDoInJava"):[Java Thread Life Cycle and Thread States](https://howtodoinJava.com/Java/multi-threading/Java-thread-life-cycle-and-thread-states/ "Java Thread Life Cycle and Thread States")),所以 Java 系统一般将这两个状态统称为 **RUNNABLE(运行中)** 状态 。
|
> 在操作系统层面,线程有 READY 和 RUNNING 状态;而在 JVM 层面,只能看到 RUNNABLE 状态(图源:[HowToDoInJava](https://howtodoinJava.com/ "HowToDoInJava"):[Java Thread Life Cycle and Thread States](https://howtodoinJava.com/Java/multi-threading/Java-thread-life-cycle-and-thread-states/ "Java Thread Life Cycle and Thread States")),所以 Java 系统一般将这两个状态统称为 **RUNNABLE(运行中)** 状态 。
|
||||||
>
|
>
|
||||||
> **为什么 JVM 没有区分这两种状态呢?** (摘自:[java线程运行怎么有第六种状态? - Dawell的回答](https://www.zhihu.com/question/56494969/answer/154053599) ) 现在的<b>时分</b>(time-sharing)<b>多任务</b>(multi-task)操作系统架构通常都是用所谓的“<b>时间分片</b>(time quantum or time slice)”方式进行<b>抢占式</b>(preemptive)轮转调度(round-robin式)。这个时间分片通常是很小的,一个线程一次最多只能在 CPU 上运行比如 10-20ms 的时间(此时处于 running 状态),也即大概只有 0.01 秒这一量级,时间片用后就要被切换下来放入调度队列的末尾等待再次调度。(也即回到 ready 状态)。线程切换的如此之快,区分这两种状态就没什么意义了。
|
> **为什么 JVM 没有区分这两种状态呢?** (摘自:[java线程运行怎么有第六种状态? - Dawell的回答](https://www.zhihu.com/question/56494969/answer/154053599) ) 现在的<b>时分</b>(time-sharing)<b>多任务</b>(multi-task)操作系统架构通常都是用所谓的“<b>时间分片</b>(time quantum or time slice)”方式进行<b>抢占式</b>(preemptive)轮转调度(round-robin式)。这个时间分片通常是很小的,一个线程一次最多只能在 CPU 上运行比如 10-20ms 的时间(此时处于 running 状态),也即大概只有 0.01 秒这一量级,时间片用后就要被切换下来放入调度队列的末尾等待再次调度。(也即回到 ready 状态)。线程切换的如此之快,区分这两种状态就没什么意义了。
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ public class ThreadPoolExecutorDemo {
|
|||||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
//创建WorkerThread对象(WorkerThread类实现了Runnable 接口)
|
//创建 MyRunnable 对象(MyRunnable 类实现了Runnable 接口)
|
||||||
Runnable worker = new MyRunnable("" + i);
|
Runnable worker = new MyRunnable("" + i);
|
||||||
//执行Runnable
|
//执行Runnable
|
||||||
executor.execute(worker);
|
executor.execute(worker);
|
||||||
|
@ -26,7 +26,7 @@ head:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
**CPU Cache 的工作方式:** 先复制一份数据到 CPU Cache 中,当 CPU 需要用到的时候就可以直接从 CPU Cache 中读取数据,当运算完成后,再将运算得到的数据写回 Main Memory 中。但是,这样存在 **内存缓存不一致性的问题** !比如我执行一个 i++操作的话,如果两个线程同时执行的话,假设两个线程从 CPU Cache 中读取的 i=1,两个线程做了 1++运算完之后再写回 Main Memory 之后 i=2,而正确结果应该是 i=3。
|
**CPU Cache 的工作方式:** 先复制一份数据到 CPU Cache 中,当 CPU 需要用到的时候就可以直接从 CPU Cache 中读取数据,当运算完成后,再将运算得到的数据写回 Main Memory 中。但是,这样存在 **内存缓存不一致性的问题** !比如我执行一个 i++ 操作的话,如果两个线程同时执行的话,假设两个线程从 CPU Cache 中读取的 i=1,两个线程做了 1++ 运算完之后再写回 Main Memory 之后 i=2,而正确结果应该是 i=3。
|
||||||
|
|
||||||
**CPU 为了解决内存缓存不一致性问题可以通过制定缓存一致协议(比如 [MESI 协议](https://zh.wikipedia.org/wiki/MESI%E5%8D%8F%E8%AE%AE))或者其他手段来解决。** 这个缓存缓存一致性协议指的是在 CPU 高速缓存与主内存交互的时候需要准守的原则和规范。不同的 CPU 中,使用的缓存一致性协议通常也会有所不同。
|
**CPU 为了解决内存缓存不一致性问题可以通过制定缓存一致协议(比如 [MESI 协议](https://zh.wikipedia.org/wiki/MESI%E5%8D%8F%E8%AE%AE))或者其他手段来解决。** 这个缓存缓存一致性协议指的是在 CPU 高速缓存与主内存交互的时候需要准守的原则和规范。不同的 CPU 中,使用的缓存一致性协议通常也会有所不同。
|
||||||
|
|
||||||
|
@ -30,25 +30,6 @@ icon: "xitongsheji"
|
|||||||
- **[Caffeine](https://github.com/ben-manes/caffeine)** : 一款强大的本地缓存解决方案,性能非常 🐂。
|
- **[Caffeine](https://github.com/ben-manes/caffeine)** : 一款强大的本地缓存解决方案,性能非常 🐂。
|
||||||
- **[Redis](https://github.com/redis/redis)** :一个使用 C 语言开发的内存数据库,分布式缓存首选。
|
- **[Redis](https://github.com/redis/redis)** :一个使用 C 语言开发的内存数据库,分布式缓存首选。
|
||||||
|
|
||||||
### 数据库建模
|
|
||||||
|
|
||||||
- **[CHINER](https://gitee.com/robergroup/chiner)** :开源免费的国产数据库建模工具。目标是做一款丰富数据库生态,独立于具体数据库之外的,数据库关系模型设计平台。前生是 [PDMan](https://gitee.com/robergroup/pdman),定位为 PowerDesigner 的免费替代方案。
|
|
||||||
|
|
||||||
开源的数据库建模工具比较少,以下是一些非开源的数据库建模工具(部分需要付费才能使用) :
|
|
||||||
|
|
||||||
- **[MySQL Workbench](https://www.mysql.com/products/workbench/)** : MySQL 官方为数据库架构师、开发人员和 DBA 提供的一个可视化工具。 MySQL Workbench 支持数据建模,SQL 开发以及服务器配置、用户管理、性能优化、数据库备份以及迁移等功能,支持 Windows、Linux 和 Mac OS X 平台。
|
|
||||||
- **[Navicat Data Modeler](https://www.navicat.com.cn/products/navicat-data-modeler)** : 一款强大的和符合成本效益的数据库设计工具,它能帮助用户创建高质素的概念、逻辑和物理数据模型。让你可视化地设计数据库结构、执行逆向或正向工程程序、从 ODBC 数据源导入模型、生成复杂的 SQL/DDL 和打印模型到文件等。付费。
|
|
||||||
- **[DbSchema](https://dbschema.com/)** : 一款功能强大的数据库设计和管理的可视化工具,支持几乎所有的关系型和 NoSQL 数据库。付费。
|
|
||||||
- **[dbdiagram.io](https://dbdiagram.io/home)** : 是一款简单免费的在线 ER 图绘制工具,通过编写代码创建模型,专为开发人员和数据分析师而设计。它通过一个简单的自定义语言来生成数据模型,支持 MySQL、PostgreSQL、SQL Server 数据库 DDL 文件的正向工程和逆向工程、版本历史、在线共享、导出图片或者 PDF 等功能。dbdiagram.io 提供了免费版。
|
|
||||||
|
|
||||||
### 数据库管理
|
|
||||||
|
|
||||||
- **[Beekeeper Studio](https://github.com/beekeeper-studio/beekeeper-studio)** :跨平台数据库管理工具,颜值高,支持 SQLite、MySQL、MariaDB、Postgres、CockroachDB、SQL Server、Amazon Redshift。
|
|
||||||
- **[Sequel Pro](https://github.com/sequelpro/sequelpro)** :适用于 macOS 的 MySQL/MariaDB 数据库管理工具。
|
|
||||||
- **[DBeaver](https://github.com/dbeaver/dbeaver)** :一个基于 Java 开发 ,并且支持几乎所有的数据库产品的开源数据库管理工具。DBeaver 社区版不光支持关系型数据库比如 MySQL、PostgreSQL、MariaDB、SQLite、Oracle、Db2、SQL Server,还比如 SQLite、H2 这些内嵌数据库。还支持常见的全文搜索引擎比如 Elasticsearch 和 Solr、大数据相关的工具比如 Hive 和 Spark。
|
|
||||||
- **[Kangaroo](https://gitee.com/dbkangaroo/kangaroo)** :袋鼠 是一款为热门数据库系统打造的管理客户端(SQLite / MySQL / PostgreSQL / ...) ,支持建表、查询、模型、同步、导入导出等功能,支持 Windows / Mac / Linux 等操作系统,力求打造成好用、好玩、开发友好的 SQL 工具。
|
|
||||||
- **[Mongood](https://github.com/RenzHoly/Mongood)** : MongoDB 图形化的管理工具。基于微软 Fluent UI,支持自动黑暗模式。
|
|
||||||
|
|
||||||
### 数据同步
|
### 数据同步
|
||||||
|
|
||||||
- **[Canal](https://github.com/alibaba/canal "canal")** [kə'næl] : Canal 译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费。
|
- **[Canal](https://github.com/alibaba/canal "canal")** [kə'næl] : Canal 译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费。
|
||||||
|
@ -4,26 +4,47 @@ category: 开源项目
|
|||||||
icon: tool
|
icon: tool
|
||||||
---
|
---
|
||||||
|
|
||||||
## Java 相关
|
## Java
|
||||||
|
|
||||||
- **[JADX](https://github.com/skylot/jadx)** :一款功能强大的反编译工具。
|
- **[JADX](https://github.com/skylot/jadx)** :一款功能强大的反编译工具。
|
||||||
- **[Recaf](https://github.com/Col-E/Recaf)** : Java 字节码编辑器,基于 ASM(Java 字节码操作框架) 来修改字节码,可简化编辑已编译 Java 应用程序的过程。
|
- **[Recaf](https://github.com/Col-E/Recaf)** : Java 字节码编辑器,基于 ASM(Java 字节码操作框架) 来修改字节码,可简化编辑已编译 Java 应用程序的过程。
|
||||||
|
|
||||||
## Redis 可视化管理
|
## 数据库
|
||||||
|
|
||||||
|
### 数据库建模
|
||||||
|
|
||||||
|
- **[CHINER](https://gitee.com/robergroup/chiner)** :开源免费的国产数据库建模工具。目标是做一款丰富数据库生态,独立于具体数据库之外的,数据库关系模型设计平台。前生是 [PDMan](https://gitee.com/robergroup/pdman),定位为 PowerDesigner 的免费替代方案。
|
||||||
|
|
||||||
|
开源的数据库建模工具比较少,以下是一些非开源的数据库建模工具(部分需要付费才能使用) :
|
||||||
|
|
||||||
|
- **[MySQL Workbench](https://www.mysql.com/products/workbench/)** : MySQL 官方为数据库架构师、开发人员和 DBA 提供的一个可视化工具。 MySQL Workbench 支持数据建模,SQL 开发以及服务器配置、用户管理、性能优化、数据库备份以及迁移等功能,支持 Windows、Linux 和 Mac OS X 平台。
|
||||||
|
- **[Navicat Data Modeler](https://www.navicat.com.cn/products/navicat-data-modeler)** : 一款强大的和符合成本效益的数据库设计工具,它能帮助用户创建高质素的概念、逻辑和物理数据模型。让你可视化地设计数据库结构、执行逆向或正向工程程序、从 ODBC 数据源导入模型、生成复杂的 SQL/DDL 和打印模型到文件等。付费。
|
||||||
|
- **[DbSchema](https://dbschema.com/)** : 一款功能强大的数据库设计和管理的可视化工具,支持几乎所有的关系型和 NoSQL 数据库。付费。
|
||||||
|
- **[dbdiagram.io](https://dbdiagram.io/home)** : 是一款简单免费的在线 ER 图绘制工具,通过编写代码创建模型,专为开发人员和数据分析师而设计。它通过一个简单的自定义语言来生成数据模型,支持 MySQL、PostgreSQL、SQL Server 数据库 DDL 文件的正向工程和逆向工程、版本历史、在线共享、导出图片或者 PDF 等功能。dbdiagram.io 提供了免费版。
|
||||||
|
|
||||||
|
### 数据库管理
|
||||||
|
|
||||||
|
- **[Beekeeper Studio](https://github.com/beekeeper-studio/beekeeper-studio)** :跨平台数据库管理工具,颜值高,支持 SQLite、MySQL、MariaDB、Postgres、CockroachDB、SQL Server、Amazon Redshift。
|
||||||
|
- **[Sequel Pro](https://github.com/sequelpro/sequelpro)** :适用于 macOS 的 MySQL/MariaDB 数据库管理工具。
|
||||||
|
- **[DBeaver](https://github.com/dbeaver/dbeaver)** :一个基于 Java 开发 ,并且支持几乎所有的数据库产品的开源数据库管理工具。DBeaver 社区版不光支持关系型数据库比如 MySQL、PostgreSQL、MariaDB、SQLite、Oracle、Db2、SQL Server,还比如 SQLite、H2 这些内嵌数据库。还支持常见的全文搜索引擎比如 Elasticsearch 和 Solr、大数据相关的工具比如 Hive 和 Spark。
|
||||||
|
- **[Kangaroo](https://gitee.com/dbkangaroo/kangaroo)** :袋鼠是一款为热门数据库系统打造的管理客户端(SQLite / MySQL / PostgreSQL / ...) ,支持建表、查询、模型、同步、导入导出等功能,支持 Windows / Mac / Linux 等操作系统,力求打造成好用、好玩、开发友好的 SQL 工具。
|
||||||
|
- **[Arctype](https://arctype.com/)** :一个桌面的数据库查询工具,可以连接各种数据库,在其中执行 SQL 语句,以可视化形式展示数据。
|
||||||
|
- **[Mongood](https://github.com/RenzHoly/Mongood)** : MongoDB 图形化的管理工具。基于微软 Fluent UI,支持自动黑暗模式。
|
||||||
|
|
||||||
|
### Redis
|
||||||
|
|
||||||
- **[Another Redis Desktop Manager](https://github.com/qishibo/AnotherRedisDesktopManager/blob/master/README.zh-CN.md)** :更快、更好、更稳定的 Redis 桌面(GUI)管理客户端。
|
- **[Another Redis Desktop Manager](https://github.com/qishibo/AnotherRedisDesktopManager/blob/master/README.zh-CN.md)** :更快、更好、更稳定的 Redis 桌面(GUI)管理客户端。
|
||||||
- **[Redis Manager](https://github.com/ngbdf/redis-manager)** :Redis 一站式管理平台,支持集群(cluster、master-replica、sentinel)的监控、安装(除 sentinel)、管理、告警以及基本的数据操作功能。
|
- **[Redis Manager](https://github.com/ngbdf/redis-manager)** :Redis 一站式管理平台,支持集群(cluster、master-replica、sentinel)的监控、安装(除 sentinel)、管理、告警以及基本的数据操作功能。
|
||||||
|
|
||||||
## Docker & Kubernetes 可视化管理
|
## Devops
|
||||||
|
|
||||||
- **[Portainer](https://github.com/portainer/portainer)** :可视化管理 Docker 和 Kubernetes。相关阅读:[《吊炸天的 Docker 图形化工具 Portainer,必须推荐给你!》](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247504221&idx=1&sn=85a3c69d64fba1b0d6d8485ab28ab4c4&chksm=cea19e96f9d617802920d5769bafc824b3b80afdfb6166a00532f0caa3b6f5bdac930e4e89de&token=693114125&lang=zh_CN#rd)。
|
- **[Portainer](https://github.com/portainer/portainer)** :可视化管理 Docker 和 Kubernetes。相关阅读:[《吊炸天的 Docker 图形化工具 Portainer,必须推荐给你!》](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247504221&idx=1&sn=85a3c69d64fba1b0d6d8485ab28ab4c4&chksm=cea19e96f9d617802920d5769bafc824b3b80afdfb6166a00532f0caa3b6f5bdac930e4e89de&token=693114125&lang=zh_CN#rd)。
|
||||||
|
|
||||||
## ZooKeeper 可视化管理
|
## ZooKeeper
|
||||||
|
|
||||||
- **[PrettyZoo](https://github.com/vran-dev/PrettyZoo)** : 一个基于 Apache Curator 和 JavaFX 实现的 ZooKeeper 图形化管理客户端,颜值非常高,支持 Mac / Windows / Linux 。你可以使用 PrettyZoo 来实现对 ZooKeeper 的可视化增删改查。
|
- **[PrettyZoo](https://github.com/vran-dev/PrettyZoo)** : 一个基于 Apache Curator 和 JavaFX 实现的 ZooKeeper 图形化管理客户端,颜值非常高,支持 Mac / Windows / Linux 。你可以使用 PrettyZoo 来实现对 ZooKeeper 的可视化增删改查。
|
||||||
- **[zktools](https://zktools.readthedocs.io/en/latest/#installing)** : 一个低延迟的 ZooKeeper 图形化管理客户端,颜值非常高,支持 Mac / Windows / Linux 。你可以使用 zktools 来实现对 ZooKeeper 的可视化增删改查。
|
- **[zktools](https://zktools.readthedocs.io/en/latest/#installing)** : 一个低延迟的 ZooKeeper 图形化管理客户端,颜值非常高,支持 Mac / Windows / Linux 。你可以使用 zktools 来实现对 ZooKeeper 的可视化增删改查。
|
||||||
|
|
||||||
|
|
||||||
## Markdown
|
## Markdown
|
||||||
|
|
||||||
- **[MarkText](https://github.com/marktext/marktext)** :一个简单而优雅的开源 Markdown 编辑器,专注于速度和可用性。Linux、macOS 和 Windows 均适用。
|
- **[MarkText](https://github.com/marktext/marktext)** :一个简单而优雅的开源 Markdown 编辑器,专注于速度和可用性。Linux、macOS 和 Windows 均适用。
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: Netty常见面试题总结
|
title: Netty常见面试题总结(付费)
|
||||||
category: 框架
|
category: 框架
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: SpringBoot常见面试题总结
|
title: SpringBoot常见面试题总结(付费)
|
||||||
category: 框架
|
category: 框架
|
||||||
tag:
|
tag:
|
||||||
- Spring
|
- Spring
|
||||||
|
@ -6,13 +6,12 @@ tag:
|
|||||||
---
|
---
|
||||||
|
|
||||||
> 本文授权转载自 : https://ken.io/note/sso-design-implement 作者:ken.io
|
> 本文授权转载自 : https://ken.io/note/sso-design-implement 作者:ken.io
|
||||||
>
|
|
||||||
|
|
||||||
## 一、前言
|
## SSO 介绍
|
||||||
|
|
||||||
### 1、SSO说明
|
### 什么是 SSO?
|
||||||
|
|
||||||
SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。https://baike.baidu.com/item/SSO/3451380
|
SSO 英文全称 Single Sign On,单点登录。SSO 是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。https://baike.baidu.com/item/SSO/3451380
|
||||||
|
|
||||||
例如访问在网易账号中心(https://reg.163.com/ )登录之后
|
例如访问在网易账号中心(https://reg.163.com/ )登录之后
|
||||||
访问以下站点都是登录状态
|
访问以下站点都是登录状态
|
||||||
@ -21,17 +20,17 @@ SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,
|
|||||||
- 网易博客 [https://blog.163.com](https://blog.163.com/)
|
- 网易博客 [https://blog.163.com](https://blog.163.com/)
|
||||||
- 网易花田 [https://love.163.com](https://love.163.com/)
|
- 网易花田 [https://love.163.com](https://love.163.com/)
|
||||||
- 网易考拉 [https://www.kaola.com](https://www.kaola.com/)
|
- 网易考拉 [https://www.kaola.com](https://www.kaola.com/)
|
||||||
- 网易Lofter [http://www.lofter.com](http://www.lofter.com/)
|
- 网易 Lofter [http://www.lofter.com](http://www.lofter.com/)
|
||||||
|
|
||||||
### 2、单点登录系统的好处
|
### SSO 有什么好处?
|
||||||
|
|
||||||
1. **用户角度** :用户能够做到一次登录多次使用,无需记录多套用户名和密码,省心。
|
1. **用户角度** :用户能够做到一次登录多次使用,无需记录多套用户名和密码,省心。
|
||||||
2. **系统管理员角度** : 管理员只需维护好一个统一的账号中心就可以了,方便。
|
2. **系统管理员角度** : 管理员只需维护好一个统一的账号中心就可以了,方便。
|
||||||
3. **新系统开发角度:** 新系统开发时只需直接对接统一的账号中心即可,简化开发流程,省时。
|
3. **新系统开发角度:** 新系统开发时只需直接对接统一的账号中心即可,简化开发流程,省时。
|
||||||
|
|
||||||
### 3、设计目标
|
## SSO 设计与实现
|
||||||
|
|
||||||
本篇文章也主要是为了探讨如何设计&实现一个SSO系统
|
本篇文章也主要是为了探讨如何设计&实现一个 SSO 系统
|
||||||
|
|
||||||
以下为需要实现的核心功能:
|
以下为需要实现的核心功能:
|
||||||
|
|
||||||
@ -40,88 +39,85 @@ SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,
|
|||||||
- 支持跨域单点登录
|
- 支持跨域单点登录
|
||||||
- 支持跨域单点登出
|
- 支持跨域单点登出
|
||||||
|
|
||||||
## 二、SSO设计与实现
|
### 核心应用与依赖
|
||||||
|
|
||||||
### 1、核心应用与依赖
|

|
||||||
|
|
||||||

|
| 应用/模块/对象 | 说明 |
|
||||||
|
| ----------------- | ----------------------------------- |
|
||||||
|
| 前台站点 | 需要登录的站点 |
|
||||||
|
| SSO 站点-登录 | 提供登录的页面 |
|
||||||
|
| SSO 站点-登出 | 提供注销登录的入口 |
|
||||||
|
| SSO 服务-登录 | 提供登录服务 |
|
||||||
|
| SSO 服务-登录状态 | 提供登录状态校验/登录信息查询的服务 |
|
||||||
|
| SSO 服务-登出 | 提供用户注销登录的服务 |
|
||||||
|
| 数据库 | 存储用户账户信息 |
|
||||||
|
| 缓存 | 存储用户的登录信息,通常使用 Redis |
|
||||||
|
|
||||||
| 应用/模块/对象 | 说明 |
|
### 用户登录状态的存储与校验
|
||||||
| ---------------- | ----------------------------------- |
|
|
||||||
| 前台站点 | 需要登录的站点 |
|
|
||||||
| SSO站点-登录 | 提供登录的页面 |
|
|
||||||
| SSO站点-登出 | 提供注销登录的入口 |
|
|
||||||
| SSO服务-登录 | 提供登录服务 |
|
|
||||||
| SSO服务-登录状态 | 提供登录状态校验/登录信息查询的服务 |
|
|
||||||
| SSO服务-登出 | 提供用户注销登录的服务 |
|
|
||||||
| 数据库 | 存储用户账户信息 |
|
|
||||||
| 缓存 | 存储用户的登录信息,通常使用Redis |
|
|
||||||
|
|
||||||
### 2、用户登录状态的存储与校验
|
常见的 Web 框架对于 Session 的实现都是生成一个 SessionId 存储在浏览器 Cookie 中。然后将 Session 内容存储在服务器端内存中,这个 [ken.io](https://ken.io/) 在之前[Session 工作原理](https://ken.io/note/session-principle-skill)中也提到过。整体也是借鉴这个思路。
|
||||||
|
|
||||||
常见的Web框架对于[Session](https://ken.io/note/session-principle-skill)的实现都是生成一个SessionId存储在浏览器Cookie中。然后将Session内容存储在服务器端内存中,这个 ken.io 在之前[Session工作原理](https://ken.io/note/session-principle-skill)中也提到过。整体也是借鉴这个思路。
|
用户登录成功之后,生成 AuthToken 交给客户端保存。如果是浏览器,就保存在 Cookie 中。如果是手机 App 就保存在 App 本地缓存中。本篇主要探讨基于 Web 站点的 SSO。
|
||||||
用户登录成功之后,生成AuthToken交给客户端保存。如果是浏览器,就保存在Cookie中。如果是手机App就保存在App本地缓存中。本篇主要探讨基于Web站点的SSO。
|
|
||||||
用户在浏览需要登录的页面时,客户端将AuthToken提交给SSO服务校验登录状态/获取用户登录信息
|
|
||||||
|
|
||||||
对于登录信息的存储,建议采用Redis,使用Redis集群来存储登录信息,既可以保证高可用,又可以线性扩充。同时也可以让SSO服务满足负载均衡/可伸缩的需求。
|
用户在浏览需要登录的页面时,客户端将 AuthToken 提交给 SSO 服务校验登录状态/获取用户登录信息
|
||||||
|
|
||||||
|
对于登录信息的存储,建议采用 Redis,使用 Redis 集群来存储登录信息,既可以保证高可用,又可以线性扩充。同时也可以让 SSO 服务满足负载均衡/可伸缩的需求。
|
||||||
|
|
||||||
| 对象 | 说明 |
|
| 对象 | 说明 |
|
||||||
| --------- | ------------------------------------------------------------ |
|
| --------- | ------------------------------------------------------------ |
|
||||||
| AuthToken | 直接使用UUID/GUID即可,如果有验证AuthToken合法性需求,可以将UserName+时间戳加密生成,服务端解密之后验证合法性 |
|
| AuthToken | 直接使用 UUID/GUID 即可,如果有验证 AuthToken 合法性需求,可以将 UserName+时间戳加密生成,服务端解密之后验证合法性 |
|
||||||
| 登录信息 | 通常是将UserId,UserName缓存起来 |
|
| 登录信息 | 通常是将 UserId,UserName 缓存起来 |
|
||||||
|
|
||||||
### 3、用户登录/登录校验
|
### 用户登录/登录校验
|
||||||
|
|
||||||
- 登录时序图
|
**登录时序图**
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
按照上图,用户登录后AuthToken保存在Cookie中。 domain=test.com
|
按照上图,用户登录后 AuthToken 保存在 Cookie 中。 domain=test.com
|
||||||
浏览器会将domain设置成 .test.com,
|
浏览器会将 domain 设置成 .test.com,
|
||||||
这样访问所有*.test.com的web站点,都会将AuthToken携带到服务器端。
|
|
||||||
然后通过SSO服务,完成对用户状态的校验/用户登录信息的获取
|
|
||||||
|
|
||||||
- 登录信息获取/登录状态校验
|
这样访问所有 \*.test.com 的 web 站点,都会将 AuthToken 携带到服务器端。
|
||||||
|
然后通过 SSO 服务,完成对用户状态的校验/用户登录信息的获取
|
||||||
|
|
||||||

|
**登录信息获取/登录状态校验**
|
||||||
|
|
||||||
### 4、用户登出
|

|
||||||
|
|
||||||
|
### 用户登出
|
||||||
|
|
||||||
用户登出时要做的事情很简单:
|
用户登出时要做的事情很简单:
|
||||||
|
|
||||||
1. 服务端清除缓存(Redis)中的登录状态
|
1. 服务端清除缓存(Redis)中的登录状态
|
||||||
2. 客户端清除存储的AuthToken
|
2. 客户端清除存储的 AuthToken
|
||||||
|
|
||||||
- 登出时序图
|
**登出时序图**
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### 5、跨域登录、登出
|
### 跨域登录、登出
|
||||||
|
|
||||||
前面提到过,核心思路是客户端存储AuthToken,服务器端通过Redis存储登录信息。由于客户端是将AuthToken存储在Cookie中的。所以跨域要解决的问题,就是如何解决Cookie的跨域读写问题。
|
前面提到过,核心思路是客户端存储 AuthToken,服务器端通过 Redis 存储登录信息。由于客户端是将 AuthToken 存储在 Cookie 中的。所以跨域要解决的问题,就是如何解决 Cookie 的跨域读写问题。
|
||||||
|
|
||||||
解决跨域的核心思路就是:
|
解决跨域的核心思路就是:
|
||||||
|
|
||||||
- 登录完成之后通过回调的方式,将AuthToken传递给主域名之外的站点,该站点自行将AuthToken保存在当前域下的Cookie中。
|
- 登录完成之后通过回调的方式,将 AuthToken 传递给主域名之外的站点,该站点自行将 AuthToken 保存在当前域下的 Cookie 中。
|
||||||
- 登出完成之后通过回调的方式,调用非主域名站点的登出页面,完成设置Cookie中的AuthToken过期的操作。
|
- 登出完成之后通过回调的方式,调用非主域名站点的登出页面,完成设置 Cookie 中的 AuthToken 过期的操作。
|
||||||
- 跨域登录(主域名已登录)
|
|
||||||
|
|
||||||

|
**跨域登录(主域名已登录)**
|
||||||
|
|
||||||
- 跨域登录(主域名未登录)
|

|
||||||
|
|
||||||

|
**跨域登录(主域名未登录)**
|
||||||
|
|
||||||
- 跨域登出
|

|
||||||
|
|
||||||

|
**跨域登出**
|
||||||
|
|
||||||
## 三、备注
|

|
||||||
|
|
||||||
- 关于方案
|
## 说明
|
||||||
|
|
||||||
这次设计方案更多是提供实现思路。如果涉及到APP用户登录等情况,在访问SSO服务时,增加对APP的签名验证就好了。当然,如果有无线网关,验证签名不是问题。
|
- 关于方案 :这次设计方案更多是提供实现思路。如果涉及到 APP 用户登录等情况,在访问 SSO 服务时,增加对 APP 的签名验证就好了。当然,如果有无线网关,验证签名不是问题。
|
||||||
|
- 关于时序图:时序图中并没有包含所有场景,只列举了核心/主要场景,另外对于一些不影响理解思路的消息能省就省了。
|
||||||
- 关于时序图
|
|
||||||
|
|
||||||
时序图中并没有包含所有场景,ken.io只列举了核心/主要场景,另外对于一些不影响理解思路的消息能省就省了。
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 系统设计常见面试题总结
|
title: 系统设计常见面试题总结(付费)
|
||||||
category: Java面试指北
|
category: Java面试指北
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 《手写 RPC 框架》
|
title: 《手写 RPC 框架》(付费)
|
||||||
category: 知识星球
|
category: 知识星球
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -39,6 +39,10 @@ category: 知识星球
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
或者你也可以直接使用下面这张 **20** 元的优惠券,**139/年** 加入。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
进入星球之后,你可以为自己制定一个目标,比如自己想要进入某某还不错的公司或者达成什么成就(一定要是还算有点挑战的目标)。待你完成目标在星球分享之后,我会将星球的门票费退还给你。
|
进入星球之后,你可以为自己制定一个目标,比如自己想要进入某某还不错的公司或者达成什么成就(一定要是还算有点挑战的目标)。待你完成目标在星球分享之后,我会将星球的门票费退还给你。
|
||||||
|
|
||||||
**真诚欢迎准备面试的小伙伴加入星球一起交流!真心希望能够帮助到更多小伙伴!**
|
**真诚欢迎准备面试的小伙伴加入星球一起交流!真心希望能够帮助到更多小伙伴!**
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 《Java 面试指北》
|
title: 《Java 面试指北》(付费)
|
||||||
category: 知识星球
|
category: 知识星球
|
||||||
star: 5
|
star: 5
|
||||||
---
|
---
|
||||||
@ -88,6 +88,10 @@ star: 5
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
或者你也可以直接使用下面这张 **20** 元的优惠券,**139/年** 加入。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
进入星球之后,你可以为自己制定一个目标,比如自己想要进入某某还不错的公司或者达成什么成就(一定要是还算有点挑战的目标)。待你完成目标在星球分享之后,我会将星球的门票费退还给你。
|
进入星球之后,你可以为自己制定一个目标,比如自己想要进入某某还不错的公司或者达成什么成就(一定要是还算有点挑战的目标)。待你完成目标在星球分享之后,我会将星球的门票费退还给你。
|
||||||
|
|
||||||
**真诚欢迎准备面试的小伙伴加入星球一起交流!真心希望能够帮助到更多小伙伴!**
|
**真诚欢迎准备面试的小伙伴加入星球一起交流!真心希望能够帮助到更多小伙伴!**
|
||||||
|
@ -38,6 +38,10 @@ category: 知识星球
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
或者你也可以直接使用下面这张 **20** 元的优惠券,**139/年** 加入。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
进入星球之后,你可以为自己制定一个目标,比如自己想要进入某某还不错的公司或者达成什么成就(一定要是还算有点挑战的目标)。待你完成目标在星球分享之后,我会将星球的门票费退还给你。
|
进入星球之后,你可以为自己制定一个目标,比如自己想要进入某某还不错的公司或者达成什么成就(一定要是还算有点挑战的目标)。待你完成目标在星球分享之后,我会将星球的门票费退还给你。
|
||||||
|
|
||||||
**真诚欢迎准备面试的小伙伴加入星球一起交流!真心希望能够帮助到更多小伙伴!**
|
**真诚欢迎准备面试的小伙伴加入星球一起交流!真心希望能够帮助到更多小伙伴!**
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 《Java 必读源码系列》
|
title: 《Java 必读源码系列》(付费)
|
||||||
category: 知识星球
|
category: 知识星球
|
||||||
star: true
|
star: true
|
||||||
---
|
---
|
||||||
@ -46,6 +46,10 @@ star: true
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
或者你也可以直接使用下面这张 **20** 元的优惠券,**139/年** 加入。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
进入星球之后,你可以为自己制定一个目标,比如自己想要进入某某还不错的公司或者达成什么成就(一定要是还算有点挑战的目标)。待你完成目标在星球分享之后,我会将星球的门票费退还给你。
|
进入星球之后,你可以为自己制定一个目标,比如自己想要进入某某还不错的公司或者达成什么成就(一定要是还算有点挑战的目标)。待你完成目标在星球分享之后,我会将星球的门票费退还给你。
|
||||||
|
|
||||||
**真诚欢迎准备面试的小伙伴加入星球一起交流!真心希望能够帮助到更多小伙伴!**
|
**真诚欢迎准备面试的小伙伴加入星球一起交流!真心希望能够帮助到更多小伙伴!**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user