docs: prettify code
This commit is contained in:
parent
e909ca2b88
commit
f1bab50f64
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1,6 +1 @@
|
||||
努力编写中...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1,4 +1,5 @@
|
||||
# GenericTokenParser
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读工程: [SourceHot-Mybatis](https://github.com/SourceHot/mybatis-read.git)
|
||||
|
||||
@ -120,9 +121,9 @@ public class GenericTokenParser {
|
||||
|
||||
```
|
||||
|
||||
|
||||
- 一个具体的例子`org.apache.ibatis.builder.SqlSourceBuilder.ParameterMappingTokenHandler`
|
||||
- 具体类`org.apache.ibatis.builder.SqlSourceBuilder`
|
||||
- 具体类`org.apache.ibatis.builder.SqlSourceBuilder`
|
||||
|
||||
```java
|
||||
/**
|
||||
* ? 的来源
|
||||
@ -137,6 +138,7 @@ public class GenericTokenParser {
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```java
|
||||
/**
|
||||
* sql 参数类型 , 返回值
|
||||
@ -173,4 +175,4 @@ public class GenericTokenParser {
|
||||
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
@ -1 +1 @@
|
||||
努力编写中......
|
||||
努力编写中......
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1,33 +1,38 @@
|
||||
|
||||
## Netty 的线程模型
|
||||
Netty线程模型 的设计,也是基于 Reactor模型,尽管不同的 NIO框架 对于 Reactor模式 的实现存在差异,但本质上还是遵循了 Reactor 的基础线程模型。
|
||||
|
||||
Netty 线程模型 的设计,也是基于 Reactor 模型,尽管不同的 NIO 框架 对于 Reactor 模式 的实现存在差异,但本质上还是遵循了 Reactor 的基础线程模型。
|
||||
|
||||
#### Reactor 单线程模型
|
||||
Reactor单线程模型,是指所有的 I/O操作 都在同一个 NIO线程 上完成。NIO线程 的职责如下。
|
||||
1. 作为 NIO服务端,接收客户端的 TCP连接;
|
||||
2. 作为 NIO客户端,向服务端发起 TCP连接;
|
||||
|
||||
Reactor 单线程模型,是指所有的 I/O 操作 都在同一个 NIO 线程 上完成。NIO 线程 的职责如下。
|
||||
|
||||
1. 作为 NIO 服务端,接收客户端的 TCP 连接;
|
||||
2. 作为 NIO 客户端,向服务端发起 TCP 连接;
|
||||
3. 读取通信对端的请求或者应答消息;
|
||||
4. 向通信对端发送消息请求或者应答消息。
|
||||
|
||||
理论上一个 NIO线程 可以独立处理所有 I/O操作。例如,通过 Acceptor类 接收客户端的 TCP连接,链路建立成功后,通过 Dispatch 轮询事件就绪的 Channel,将事件分发到指定的 Handler 上进行事件处理。小容量应用场景下,可以使用单线程模型。但对于高负载、大并发的应用场景并不合用。
|
||||
理论上一个 NIO 线程 可以独立处理所有 I/O 操作。例如,通过 Acceptor 类 接收客户端的 TCP 连接,链路建立成功后,通过 Dispatch 轮询事件就绪的 Channel,将事件分发到指定的 Handler 上进行事件处理。小容量应用场景下,可以使用单线程模型。但对于高负载、大并发的应用场景并不合用。
|
||||
|
||||
#### Reactor 多线程模型
|
||||
Rector多线程模型 与 单线程模型 最大的区别就是有一组 NIO线程 来处理 I/O操作,Reactor多线程模型 的特点如下。
|
||||
1. 有专门一个 NIO线程 (Acceptor线程) 用于监听服务端,接收客户端的 TCP连接请求。
|
||||
2. 网络IO操作 由一个 NIO线程池 负责,由这些 NIO线程 负责消息的 读取、解码、编码、发送。
|
||||
3. 一个 NIO线程 可以同时处理 N条链路,但是一个链路只对应一个 NIO线程,防止发生并发操作问题。
|
||||
|
||||
Reactor多线程模型 可以满足大部分场景的需求。但对于 百万级超高并发 或 服务端需要对客户端进行安全认证,但认证非常消耗资源。在这类场景下,单独一个 Acceptor线程 可能会处理不过来,成为系统的性能瓶颈。
|
||||
Rector 多线程模型 与 单线程模型 最大的区别就是有一组 NIO 线程 来处理 I/O 操作,Reactor 多线程模型 的特点如下。
|
||||
|
||||
1. 有专门一个 NIO 线程 (Acceptor 线程) 用于监听服务端,接收客户端的 TCP 连接请求。
|
||||
2. 网络 IO 操作 由一个 NIO 线程池 负责,由这些 NIO 线程 负责消息的 读取、解码、编码、发送。
|
||||
3. 一个 NIO 线程 可以同时处理 N 条链路,但是一个链路只对应一个 NIO 线程,防止发生并发操作问题。
|
||||
|
||||
Reactor 多线程模型 可以满足大部分场景的需求。但对于 百万级超高并发 或 服务端需要对客户端进行安全认证,但认证非常消耗资源。在这类场景下,单独一个 Acceptor 线程 可能会处理不过来,成为系统的性能瓶颈。
|
||||
|
||||
#### Reactor 主从多线程模型
|
||||
主从Reactor多线程模型的特点是,服务端用于接收客户端连接的是一个独立的 NIO线程池。**Acceptor线程 与客户端建立 TCP连接 后,将新的 SocketChannel 注册到 NIO线程池 的某个 NIO线程 上,由该 NIO线程 负责轮询 SocketChannel 上的 IO事件,并进行事件处理**。
|
||||
|
||||
主从 Reactor 多线程模型的特点是,服务端用于接收客户端连接的是一个独立的 NIO 线程池。**Acceptor 线程 与客户端建立 TCP 连接 后,将新的 SocketChannel 注册到 NIO 线程池 的某个 NIO 线程 上,由该 NIO 线程 负责轮询 SocketChannel 上的 IO 事件,并进行事件处理**。
|
||||
|
||||
利用 主从多线程模型,可以解决一个服务端监听线程无法有效处理所有客户端连接的性能不足问题。在 Netty 的官方 Demo 中,也是推荐使用该线程模型。
|
||||
|
||||
#### Netty 多线程编程最佳实践
|
||||
1. **如果业务逻辑比较简单,并且没有 数据库操作、线程阻塞的磁盘操作、网路操作等,可以直接在 NIO线程 上完成业务逻辑编排,不需要切换到用户线程;**
|
||||
2. **如果业务逻辑比较复杂,不要在 NIO线程 上完成,建议将解码后的 POJO消息 封装成 Task,分发到 业务线程池 中由业务线程执行,以保证 NIO线程 尽快被释放,处理其他的I/O操作。**
|
||||
|
||||
1. **如果业务逻辑比较简单,并且没有 数据库操作、线程阻塞的磁盘操作、网路操作等,可以直接在 NIO 线程 上完成业务逻辑编排,不需要切换到用户线程;**
|
||||
2. **如果业务逻辑比较复杂,不要在 NIO 线程 上完成,建议将解码后的 POJO 消息 封装成 Task,分发到 业务线程池 中由业务线程执行,以保证 NIO 线程 尽快被释放,处理其他的 I/O 操作。**
|
||||
3. **由于用户场景不同,对于一些复杂系统,很难根据 理论公式 计算出最优线程配置,只能是 结合公式给出一个相对合理的范围,然后对范围内的数据进行性能测试,选择相对最优配置。**
|
||||
|
||||
## NioEventLoop 源码解析
|
||||
@ -94,7 +99,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 轮询 事件就绪的channel,进行 IO事件处理
|
||||
*/
|
||||
@ -153,4 +158,4 @@ public final class NioEventLoop extends SingleThreadEventLoop {
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中......
|
||||
努力编写中......
|
||||
|
@ -1 +1 @@
|
||||
努力编写中......
|
||||
努力编写中......
|
||||
|
@ -1 +1 @@
|
||||
努力编写中......
|
||||
努力编写中......
|
||||
|
@ -147,4 +147,3 @@ for (int i = 0; i < 100000; i++) {
|
||||
这便是**一次完整的定时任务加入到时间轮具体位置的计算**。
|
||||
|
||||
在 worker 线程的最后,就需要来具体执行定时任务了,首先通过当前循环轮数与时间轮数组长度-1 相与的结果定位具体触发时间轮数组上哪个位置上的链表,再通过 `expireTimeouts()`方法依次对链表上的定时任务进行触发执行。这里的流程就相对很简单,链表上的节点如果 remainingRounds 小于等于 0,那么就可以直接执行这个定时任务,如果 remainingRounds 大于 0,那么显然还没有到达触发的时间点,则将其-1 等待下一轮的调度之后再进行执行。在继续回到上面的例子,当 14 点来临之时,此时工作线程将进行第 2 轮的调度,将会把 2 与 8-1 进行相与得到结果 2,那么当前工作线程就会选择时间轮数组下标为 2 的链表依次判断是否需要触发,如果 remainingRounds 为 0 将会直接触发,否则将会将 remainingRounds-1 等待下一轮的执行。
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
- chunk: 一个 chunk 是一组 page 的集合
|
||||
- 在 PoolChunk 中,chunkSize 的大小是 `2^maxOrder * pageSize`,其中 2^maxOrder 是 PoolChunk 中的完全二叉树叶子结点的数量,pageSize 则是单个 page 的大小。
|
||||
|
||||
综合如上所述,举一个数字上的例子,默认情况下,单个 Page 的大小为 8192,也就是 8kb,maxOrder 默认情况下是 11,因此在这个情况下 PoolChunk 中的二叉树的叶子节点数量是 2048,chunkSize 的大小则是 2048*8kb 为 16M。
|
||||
综合如上所述,举一个数字上的例子,默认情况下,单个 Page 的大小为 8192,也就是 8kb,maxOrder 默认情况下是 11,因此在这个情况下 PoolChunk 中的二叉树的叶子节点数量是 2048,chunkSize 的大小则是 2048\*8kb 为 16M。
|
||||
|
||||
## PoolChunk 的内部完全二叉树结构
|
||||
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1,9 +1,10 @@
|
||||
# Spring PlaceholderResolver
|
||||
|
||||
- 类全路径: `org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver`
|
||||
|
||||
- 类作用将占位符中的内容替换成属性值.
|
||||
- 假设现有属性表: user.dir = c:\home
|
||||
传入参数 user.dir 会获得 c:\home
|
||||
- 假设现有属性表: user.dir = c:\home
|
||||
传入参数 user.dir 会获得 c:\home
|
||||
|
||||
```java
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
- 类全路径: `org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.PropertyPlaceholderConfigurerResolver`
|
||||
|
||||
|
||||
- 这个类是从 Properties 中获取属性
|
||||
|
||||
```java
|
||||
@ -45,7 +44,6 @@
|
||||
|
||||
```
|
||||
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
protected String resolvePlaceholder(String placeholder, Properties props) {
|
||||
@ -53,7 +51,6 @@
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
protected String resolveSystemProperty(String key) {
|
||||
@ -72,4 +69,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -1,6 +1,5 @@
|
||||
# Spring ServletContextPlaceholderResolver
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.web.util.ServletContextPropertyUtils.ServletContextPlaceholderResolver`
|
||||
|
||||
```java
|
||||
@ -40,4 +39,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -1,8 +1,7 @@
|
||||
# Spring SystemPropertyPlaceholderResolver
|
||||
# Spring SystemPropertyPlaceholderResolver
|
||||
|
||||
- 类全路径: `org.springframework.util.SystemPropertyUtils.SystemPropertyPlaceholderResolver`
|
||||
|
||||
|
||||
```java
|
||||
private static class SystemPropertyPlaceholderResolver implements PropertyPlaceholderHelper.PlaceholderResolver {
|
||||
|
||||
@ -32,4 +31,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -3,14 +3,9 @@
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.core.env.CommandLinePropertySource`
|
||||
- 作用: 用来存储命令行参数
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public abstract class CommandLinePropertySource<T> extends EnumerablePropertySource<T> {
|
||||
|
||||
@ -93,10 +88,6 @@ public abstract class CommandLinePropertySource<T> extends EnumerablePropertySou
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## getOptionValues
|
||||
|
||||
```java
|
||||
@ -120,8 +111,6 @@ public abstract class CommandLinePropertySource<T> extends EnumerablePropertySou
|
||||
protected abstract List<String> getOptionValues(String name);
|
||||
```
|
||||
|
||||
阅读注释可以知道该方法可以获取命令行参数的列表.
|
||||
|
||||
|
||||
阅读注释可以知道该方法可以获取命令行参数的列表.
|
||||
|
||||
- 如 `--foo`作为开头当输入命令行为 `--foo=bar --foo=baz` 在输入参数名称 `foo` 会得到数据`bar,baz`
|
||||
- 如 `--foo`作为开头当输入命令行为 `--foo=bar --foo=baz` 在输入参数名称 `foo` 会得到数据`bar,baz`
|
||||
|
@ -3,12 +3,11 @@
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 整体代码如下.
|
||||
- 下面几个调用方法会直接抛出异常
|
||||
1. getSource
|
||||
1. containsProperty
|
||||
1. getProperty
|
||||
- 下面几个调用方法会直接抛出异常
|
||||
1. getSource
|
||||
1. containsProperty
|
||||
1. getProperty
|
||||
|
||||
```java
|
||||
static class ComparisonPropertySource extends StubPropertySource {
|
||||
@ -41,4 +40,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -1,11 +1,12 @@
|
||||
# Spring CompositePropertySource
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 全路径: `org.springframework.core.env.CompositePropertySource`
|
||||
|
||||
- 整体代码如下
|
||||
|
||||
```java
|
||||
public class CompositePropertySource extends EnumerablePropertySource<Object> {
|
||||
|
||||
@ -102,4 +103,4 @@ public class CompositePropertySource extends EnumerablePropertySource<Object> {
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -9,7 +9,9 @@
|
||||
```java
|
||||
public abstract String[] getPropertyNames();
|
||||
```
|
||||
|
||||
- 整体代码如下
|
||||
|
||||
```java
|
||||
public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
|
||||
|
||||
@ -27,7 +29,7 @@ public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
|
||||
* <p>This implementation checks for the presence of the given name within the
|
||||
* {@link #getPropertyNames()} array.
|
||||
*
|
||||
* 在属性列表中是否存在 properties
|
||||
* 在属性列表中是否存在 properties
|
||||
* @param name the name of the property to find
|
||||
*/
|
||||
@Override
|
||||
@ -43,4 +45,4 @@ public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
|
||||
public abstract String[] getPropertyNames();
|
||||
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -3,11 +3,9 @@
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.core.env.MapPropertySource`
|
||||
- 内部数据结构是一个`Map<String,Object>`
|
||||
这是一个对map的操作.
|
||||
|
||||
这是一个对 map 的操作.
|
||||
- 整体代码如下.
|
||||
|
||||
```java
|
||||
@ -40,4 +38,4 @@ public class MapPropertySource extends EnumerablePropertySource<Map<String, Obje
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -1,19 +1,13 @@
|
||||
# Spring MockPropertySource
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 内部 source 是 Properties 类型
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## withProperty
|
||||
|
||||
- 设置属性名称和属性值
|
||||
- 设置属性名称和属性值
|
||||
|
||||
```java
|
||||
public MockPropertySource withProperty(String name, Object value) {
|
||||
@ -22,10 +16,6 @@ public MockPropertySource withProperty(String name, Object value) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## setProperty
|
||||
|
||||
```java
|
||||
@ -34,14 +24,8 @@ public void setProperty(String name, Object value) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 完整代码
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public class MockPropertySource extends PropertiesPropertySource {
|
||||
|
||||
@ -109,4 +93,4 @@ public class MockPropertySource extends PropertiesPropertySource {
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -1,14 +1,12 @@
|
||||
# Spring PropertiesPropertySource
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 全路径: `org.springframework.core.env.PropertiesPropertySource`
|
||||
|
||||
|
||||
|
||||
- Properties 是map结构。可以做类型转换.
|
||||
- getPropertyNames 就转换成了父类MapPropertySource的方法了
|
||||
- Properties 是 map 结构。可以做类型转换.
|
||||
- getPropertyNames 就转换成了父类 MapPropertySource 的方法了
|
||||
- map.keySet()
|
||||
|
||||
```java
|
||||
@ -32,4 +30,4 @@ public class PropertiesPropertySource extends MapPropertySource {
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -1,17 +1,11 @@
|
||||
# Spring ResourcePropertySource
|
||||
# Spring ResourcePropertySource
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 全路径: `org.springframework.core.io.support.ResourcePropertySource`
|
||||
|
||||
- source 依然是map结构
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- source 依然是 map 结构
|
||||
|
||||
## getNameForResource
|
||||
|
||||
@ -27,10 +21,6 @@ private static String getNameForResource(Resource resource) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## withName
|
||||
|
||||
- 创建 ResourcePropertySource 对象, 根据 name 属性
|
||||
@ -56,10 +46,6 @@ public ResourcePropertySource withName(String name) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 构造函数
|
||||
|
||||
- 通过 location 字符串读取 resource
|
||||
@ -71,8 +57,6 @@ public ResourcePropertySource(String name, String location, ClassLoader classLoa
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 读取 resource 信息进行存储
|
||||
|
||||
```java
|
||||
@ -85,8 +69,6 @@ public ResourcePropertySource(String name, EncodedResource resource) throws IOEx
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 完整代码
|
||||
|
||||
```java
|
||||
@ -238,4 +220,4 @@ public class ResourcePropertySource extends PropertiesPropertySource {
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -3,10 +3,8 @@
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.web.context.support.ServletConfigPropertySource`
|
||||
- 内部数据结构是 `ServletConfig`
|
||||
|
||||
|
||||
- 整体代码如下
|
||||
|
||||
@ -33,4 +31,4 @@ public class ServletConfigPropertySource extends EnumerablePropertySource<Servle
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -1,16 +1,12 @@
|
||||
# Spring ServletContextPropertySource
|
||||
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.web.context.support.ServletContextPropertySource`
|
||||
- 内部数据结构是 ServletContext 接口
|
||||
|
||||
- 整体代码如下.
|
||||
|
||||
|
||||
```java
|
||||
|
||||
public class ServletContextPropertySource extends EnumerablePropertySource<ServletContext> {
|
||||
@ -34,4 +30,4 @@ public class ServletContextPropertySource extends EnumerablePropertySource<Servl
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -1,15 +1,13 @@
|
||||
# Spring SimpleCommandLineArgsParser
|
||||
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.core.env.SimpleCommandLineArgsParser
|
||||
- 类作用: 将命令行参数解析成 `org.springframework.core.env.CommandLineArgs`
|
||||
|
||||
- 完整代码如下.
|
||||
- 完整代码如下.
|
||||
|
||||
```java
|
||||
|
||||
class SimpleCommandLineArgsParser {
|
||||
@ -51,5 +49,5 @@ class SimpleCommandLineArgsParser {
|
||||
```
|
||||
|
||||
- 处理流程
|
||||
1. 循环命令行参数列表
|
||||
2. 去掉 `--` 和 `=` 获取参数名称和参数值放入结果集合
|
||||
1. 循环命令行参数列表
|
||||
2. 去掉 `--` 和 `=` 获取参数名称和参数值放入结果集合
|
||||
|
@ -2,19 +2,11 @@
|
||||
|
||||
- 全路径: `org.springframework.core.env.SimpleCommandLinePropertySource`
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {}
|
||||
```
|
||||
|
||||
- SimpleCommandLinePropertySource 的source 类型是 CommandLineArgs 具体解释请看下面分析
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- SimpleCommandLinePropertySource 的 source 类型是 CommandLineArgs 具体解释请看下面分析
|
||||
|
||||
## CommandLineArgs
|
||||
|
||||
@ -37,7 +29,7 @@ class CommandLineArgs {
|
||||
|
||||
### addOptionArg
|
||||
|
||||
添加 选项参数
|
||||
添加 选项参数
|
||||
|
||||
```java
|
||||
public void addOptionArg(String optionName, @Nullable String optionValue) {
|
||||
@ -50,8 +42,6 @@ public void addOptionArg(String optionName, @Nullable String optionValue) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### getOptionNames
|
||||
|
||||
- 获取选项参数列表
|
||||
@ -62,14 +52,8 @@ public Set<String> getOptionNames() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 其他方法不具体描述了,各位可以查看下面的代码
|
||||
|
||||
|
||||
|
||||
```java
|
||||
class CommandLineArgs {
|
||||
|
||||
@ -142,13 +126,7 @@ class CommandLineArgs {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
在了解 CommandLineArgs 类后再来看 SimpleCommandLinePropertySource 会相对容易. 内部的几个方法就是调用 CommandLineArgs 所提供的方法
|
||||
|
||||
|
||||
在了解 CommandLineArgs 类后再来看 SimpleCommandLinePropertySource 会相对容易. 内部的几个方法就是调用 CommandLineArgs 所提供的方法
|
||||
|
||||
```java
|
||||
@Override
|
||||
@ -172,4 +150,3 @@ protected List<String> getNonOptionArgs() {
|
||||
return this.source.getNonOptionArgs();
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -3,10 +3,8 @@
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
|
||||
- 整体代码如下.
|
||||
- 通过 StubPropertySource 的 getProperty 方法永远返回null
|
||||
- 整体代码如下.
|
||||
- 通过 StubPropertySource 的 getProperty 方法永远返回 null
|
||||
|
||||
```java
|
||||
public static class StubPropertySource extends PropertySource<Object> {
|
||||
@ -25,4 +23,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -1,18 +1,17 @@
|
||||
# Spring BeanDefinitionParserDelegate
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
- 全路径`org.springframework.beans.factory.xml.BeanDefinitionParserDelegate`
|
||||
- 解析 xml 中标签的委托类
|
||||
|
||||
|
||||
|
||||
- 在这个类中定义常量如下,为后续解析提供帮助
|
||||
|
||||
```java
|
||||
public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
|
||||
|
||||
public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";
|
||||
public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";
|
||||
|
||||
public static final String TRUE_VALUE = "true";
|
||||
|
||||
@ -147,18 +146,10 @@
|
||||
private static final String SINGLETON_ATTRIBUTE = "singleton";
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## populateDefaults
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#populateDefaults`方法解析属性赋值给`DocumentDefaultsDefinition`对象
|
||||
|
||||
|
||||
|
||||
- 代码逻辑如下
|
||||
1. 读取属性
|
||||
2. 判断是否默认值
|
||||
@ -215,8 +206,6 @@ protected void populateDefaults(DocumentDefaultsDefinition defaults, @Nullable D
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### DocumentDefaultsDefinition
|
||||
|
||||
- 全路径:`org.springframework.beans.factory.xml.DocumentDefaultsDefinition`
|
||||
@ -266,12 +255,6 @@ public class DocumentDefaultsDefinition implements DefaultsDefinition {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## checkNameUniqueness
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#checkNameUniqueness`
|
||||
@ -309,17 +292,13 @@ protected void checkNameUniqueness(String beanName, List<String> aliases, Elemen
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## createBeanDefinition
|
||||
|
||||
- `org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition`
|
||||
- 创建具有基本信息的**BeanDefinition**
|
||||
1. parent bean name
|
||||
1. parent bean name
|
||||
2. bean clsss
|
||||
3. bean class name
|
||||
3. bean class name
|
||||
|
||||
```java
|
||||
public static AbstractBeanDefinition createBeanDefinition(
|
||||
@ -343,29 +322,15 @@ public static AbstractBeanDefinition createBeanDefinition(
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## parseBeanDefinitionElement
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)`
|
||||
- 该方法用来解析 `<bean/>` 标签信息
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
##
|
||||
##
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, java.lang.String, org.springframework.beans.factory.config.BeanDefinition)`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
public AbstractBeanDefinition parseBeanDefinitionElement(
|
||||
@ -432,12 +397,8 @@ public AbstractBeanDefinition parseBeanDefinitionElement(
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionAttributes`
|
||||
|
||||
|
||||
|
||||
- 将 xml 标签的数据读取到内存中设置给`AbstractBeanDefinition`
|
||||
|
||||
|
||||
|
||||
```JAVA
|
||||
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
|
||||
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
|
||||
@ -539,17 +500,11 @@ public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### parseMetaElements
|
||||
|
||||
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseMetaElements`
|
||||
|
||||
- 设置元数据.
|
||||
- 设置元数据.
|
||||
|
||||
标签`meta`的解析
|
||||
|
||||
@ -578,8 +533,6 @@ public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attribu
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
使用案例
|
||||
|
||||
```xml
|
||||
@ -588,8 +541,6 @@ public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attribu
|
||||
</bean>
|
||||
```
|
||||
|
||||
|
||||
|
||||
```java
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/beans/spring-lookup-method.xml");
|
||||
|
||||
@ -599,8 +550,6 @@ Object attribute = apple.getAttribute("meta-key");
|
||||
System.out.println(attribute);
|
||||
```
|
||||
|
||||
|
||||
|
||||
### parseLookupOverrideSubElements
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseLookupOverrideSubElements`
|
||||
@ -609,8 +558,6 @@ System.out.println(attribute);
|
||||
|
||||
`lookup-method`
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
|
||||
// 获取子标签
|
||||
@ -634,8 +581,6 @@ public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides over
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
使用案例
|
||||
|
||||
```xml
|
||||
@ -659,10 +604,6 @@ public class LookupMain {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### parseReplacedMethodSubElements
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseReplacedMethodSubElements`
|
||||
@ -710,12 +651,8 @@ public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides over
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 使用案例
|
||||
|
||||
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
@ -735,8 +672,6 @@ public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides over
|
||||
</beans>
|
||||
```
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public class MethodReplacerApple implements MethodReplacer {
|
||||
@Override
|
||||
@ -747,13 +682,7 @@ public class MethodReplacerApple implements MethodReplacer {
|
||||
}
|
||||
```
|
||||
|
||||
**replacer需要使用MethodReplacer实现类**
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**replacer 需要使用 MethodReplacer 实现类**
|
||||
|
||||
### parseConstructorArgElements
|
||||
|
||||
@ -761,8 +690,6 @@ public class MethodReplacerApple implements MethodReplacer {
|
||||
|
||||
- 解析`constructor-arg`标签
|
||||
|
||||
|
||||
|
||||
```
|
||||
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
|
||||
// 获取
|
||||
@ -777,10 +704,6 @@ public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
|
||||
// 获取 index 属性
|
||||
@ -857,8 +780,6 @@ public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### parseConstructorArgElement
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseConstructorArgElement`
|
||||
@ -928,10 +849,6 @@ public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable Strin
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### parsePropertySubElement
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertySubElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)`
|
||||
@ -944,10 +861,6 @@ public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### parsePropertySubElement
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertySubElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition, java.lang.String)`
|
||||
@ -1028,13 +941,9 @@ public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd,
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### parseIdRefElement
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseIdRefElement`
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseIdRefElement`
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
@ -1058,14 +967,10 @@ public Object parseIdRefElement(Element ele) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### parseValueElement
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseValueElement`
|
||||
|
||||
|
||||
|
||||
```JAVA
|
||||
public Object parseValueElement(Element ele, @Nullable String defaultTypeName) {
|
||||
// It's a literal value.
|
||||
@ -1093,10 +998,6 @@ public Object parseIdRefElement(Element ele) {
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
##### buildTypedStringValue
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#buildTypedStringValue`
|
||||
@ -1105,7 +1006,7 @@ public Object parseIdRefElement(Element ele) {
|
||||
```java
|
||||
protected TypedStringValue buildTypedStringValue(String value, @Nullable String targetTypeName)
|
||||
throws ClassNotFoundException {
|
||||
// class loader
|
||||
// class loader
|
||||
ClassLoader classLoader = this.readerContext.getBeanClassLoader();
|
||||
TypedStringValue typedValue;
|
||||
if (!StringUtils.hasText(targetTypeName)) {
|
||||
@ -1144,8 +1045,6 @@ public Object parseArrayElement(Element arrayEle, @Nullable BeanDefinition bd) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### parseListElement
|
||||
|
||||
```java
|
||||
@ -1176,10 +1075,6 @@ public Set<Object> parseSetElement(Element collectionEle, @Nullable BeanDefiniti
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
##### parseCollectionElements
|
||||
|
||||
- `parseArrayElement`、`parseListElement`、`parseSetElement` 都围绕者下面这个方法进行数据合并
|
||||
@ -1198,8 +1093,6 @@ protected void parseCollectionElements(
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### parseMapElement
|
||||
|
||||
```java
|
||||
@ -1342,20 +1235,8 @@ public Map<Object, Object> parseMapElement(Element mapEle, @Nullable BeanDefinit
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### parsePropsElement
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### parsePropertyElement
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertyElement`
|
||||
@ -1389,12 +1270,6 @@ public void parsePropertyElement(Element ele, BeanDefinition bd) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### parseQualifierElements
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseQualifierElements`
|
||||
@ -1413,10 +1288,6 @@ public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### parseQualifierElement
|
||||
|
||||
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseQualifierElement`
|
||||
@ -1470,4 +1341,4 @@ public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
|
||||
this.parseState.pop();
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -1,14 +1,12 @@
|
||||
# Spring BeanDefinitionReaderUtils
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
|
||||
## createBeanDefinition
|
||||
|
||||
- `org.springframework.beans.factory.support.BeanDefinitionReaderUtils.createBeanDefinition`
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public static AbstractBeanDefinition createBeanDefinition(
|
||||
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
|
||||
@ -31,8 +29,6 @@ public static AbstractBeanDefinition createBeanDefinition(
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## generateBeanName
|
||||
|
||||
- `org.springframework.beans.factory.support.BeanDefinitionReaderUtils.generateBeanName(org.springframework.beans.factory.config.BeanDefinition, org.springframework.beans.factory.support.BeanDefinitionRegistry, boolean)`
|
||||
@ -77,8 +73,6 @@ public static AbstractBeanDefinition createBeanDefinition(
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## uniqueBeanName
|
||||
|
||||
```java
|
||||
@ -96,10 +90,6 @@ public static String uniqueBeanName(String beanName, BeanDefinitionRegistry regi
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## registerBeanDefinition
|
||||
|
||||
```java
|
||||
@ -125,10 +115,6 @@ public static void registerBeanDefinition(
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## registerWithGeneratedName
|
||||
|
||||
```java
|
||||
@ -142,4 +128,4 @@ public static String registerWithGeneratedName(
|
||||
registry.registerBeanDefinition(generatedName, definition);
|
||||
return generatedName;
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -1,12 +1,11 @@
|
||||
# Spring BeanNameGenerator
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- `org.springframework.beans.factory.support.BeanNameGenerator`
|
||||
- 方法用来生成 beanName
|
||||
|
||||
|
||||
```java
|
||||
public interface BeanNameGenerator {
|
||||
|
||||
@ -23,20 +22,12 @@ public interface BeanNameGenerator {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## DefaultBeanNameGenerator
|
||||
|
||||
- `org.springframework.beans.factory.support.DefaultBeanNameGenerator`
|
||||
|
||||
|
||||
|
||||
- 调用工具类方法进行生成
|
||||
|
||||
```JAVA
|
||||
@ -46,11 +37,9 @@ public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
1. ClassName + # + 十六进制字符
|
||||
2. parentName + $child + # + 十六进制字符
|
||||
3. factoryBeanName +$created+# + 十六进制字符
|
||||
2. parentName + \$child + # + 十六进制字符
|
||||
3. factoryBeanName +\$created+# + 十六进制字符
|
||||
4. beanName + # + 序号
|
||||
|
||||
```java
|
||||
@ -93,13 +82,9 @@ public static String generateBeanName(
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## AnnotationBeanNameGenerator
|
||||
|
||||
1. 获取注解的value作为beanName
|
||||
1. 获取注解的 value 作为 beanName
|
||||
2. 类名首字母小写
|
||||
|
||||
```java
|
||||
@ -122,10 +107,6 @@ public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## FullyQualifiedAnnotationBeanNameGenerator
|
||||
|
||||
- 全类名
|
||||
@ -137,4 +118,4 @@ protected String buildDefaultBeanName(BeanDefinition definition) {
|
||||
Assert.state(beanClassName != null, "No bean class name set");
|
||||
return beanClassName;
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -1,20 +1,17 @@
|
||||
# Spring MethodOverride
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- `org.springframework.beans.factory.support.MethodOverride`
|
||||
- `org.springframework.beans.factory.support.LookupOverride`
|
||||
- `org.springframework.beans.factory.support.ReplaceOverride`
|
||||
- `org.springframework.beans.factory.support.LookupOverride`
|
||||
- `org.springframework.beans.factory.support.ReplaceOverride`
|
||||
- `org.springframework.beans.factory.support.MethodOverrides`
|
||||
|
||||
|
||||
|
||||
## MethodOverride
|
||||
|
||||
- MethodOverride 方法重载类
|
||||
|
||||
|
||||
|
||||
在`MethodOverride`定义了下面三个属性
|
||||
|
||||
1. 方法名称
|
||||
@ -48,17 +45,11 @@ public abstract class MethodOverride implements BeanMetadataElement {
|
||||
public abstract boolean matches(Method method);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
类图
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
- 在Spring中有两种可以重写的机制(XML)
|
||||
- 在 Spring 中有两种可以重写的机制(XML)
|
||||
|
||||
1. `lookup-method` 标签
|
||||
|
||||
@ -66,22 +57,14 @@ public abstract boolean matches(Method method);
|
||||
<lookup-method name="" bean=""/>
|
||||
```
|
||||
|
||||
|
||||
|
||||
2. `replaced-method` 标签
|
||||
|
||||
```xml
|
||||
<replaced-method name="" replacer=""/>
|
||||
```
|
||||
|
||||
|
||||
|
||||
相对应的两个类如类图所示
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## LookupOverride
|
||||
|
||||
- `org.springframework.beans.factory.support.LookupOverride`
|
||||
@ -100,17 +83,15 @@ private final String beanName;
|
||||
private Method method;
|
||||
```
|
||||
|
||||
|
||||
|
||||
### matches
|
||||
|
||||
比较方法
|
||||
|
||||
1. method是否直接相等
|
||||
1. method 名称是否相同
|
||||
2. 是否需要重载
|
||||
3. 是不是 ABSTRACT 方法
|
||||
4. 参数列表长度是否等于0
|
||||
1. method 是否直接相等
|
||||
1. method 名称是否相同
|
||||
1. 是否需要重载
|
||||
1. 是不是 ABSTRACT 方法
|
||||
1. 参数列表长度是否等于 0
|
||||
|
||||
```java
|
||||
@Override
|
||||
@ -131,10 +112,6 @@ private Method method;
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## ReplaceOverride
|
||||
|
||||
- `org.springframework.beans.factory.support.ReplaceOverride`
|
||||
@ -152,8 +129,6 @@ private final String methodReplacerBeanName;
|
||||
private final List<String> typeIdentifiers = new LinkedList<>();
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 一个例子
|
||||
|
||||
```XML
|
||||
@ -175,18 +150,12 @@ private final List<String> typeIdentifiers = new LinkedList<>();
|
||||
</beans>
|
||||
```
|
||||
|
||||
|
||||
|
||||
methodReplacerBeanName 对应`org.springframework.beans.factory.support.MethodReplacer` 的实现类
|
||||
|
||||
typeIdentifiers 对应标签 arg-type 的属性值
|
||||
|
||||
|
||||
typeIdentifiers 对应标签 arg-type 的属性值
|
||||
|
||||
构造方法
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public ReplaceOverride(String methodName, String methodReplacerBeanName) {
|
||||
super(methodName);
|
||||
@ -195,18 +164,10 @@ public ReplaceOverride(String methodName, String methodReplacerBeanName) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
methodName 通过父类进行设置
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### matches
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Override
|
||||
public boolean matches(Method method) {
|
||||
@ -237,39 +198,27 @@ public boolean matches(Method method) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## MethodOverrides
|
||||
|
||||
- `org.springframework.beans.factory.support.MethodOverrides`
|
||||
|
||||
- 重载方法对象
|
||||
|
||||
- 存储所有重载的方法列表(set结构)
|
||||
- 存储所有重载的方法列表(set 结构)
|
||||
|
||||
```java
|
||||
private final Set<MethodOverride> overrides = new CopyOnWriteArraySet<>();
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
几个方法
|
||||
|
||||
|
||||
|
||||
1. 添加 MethodOverride
|
||||
|
||||
```java
|
||||
public void addOverride(MethodOverride override) {
|
||||
this.overrides.add(override);
|
||||
}
|
||||
|
||||
|
||||
public void addOverrides(@Nullable MethodOverrides other) {
|
||||
if (other != null) {
|
||||
this.overrides.addAll(other.overrides);
|
||||
@ -290,4 +239,4 @@ public boolean matches(Method method) {
|
||||
}
|
||||
return match;
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Spring MultiValueMap
|
||||
# Spring MultiValueMap
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
@ -53,18 +54,12 @@ public interface MultiValueMap<K, V> extends Map<K, List<V>> {
|
||||
}
|
||||
```
|
||||
|
||||
- 但从接口定义上可以明确 value 是一个list结构
|
||||
|
||||
|
||||
- 但从接口定义上可以明确 value 是一个 list 结构
|
||||
|
||||
类图
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## LinkedMultiValueMap
|
||||
|
||||
```java
|
||||
@ -78,7 +73,7 @@ public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V>, Serializa
|
||||
// 获取 list 的第一个
|
||||
return (values != null && !values.isEmpty() ? values.get(0) : null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void add(K key, @Nullable V value) {
|
||||
// 从当前内存中获取key对应的list.
|
||||
@ -86,7 +81,7 @@ public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V>, Serializa
|
||||
// 将value 插入到values中
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addAll(K key, List<? extends V> values) {
|
||||
// 从当前内存中获取key对应的list.
|
||||
@ -94,14 +89,14 @@ public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V>, Serializa
|
||||
// 将value 插入到values中
|
||||
currentValues.addAll(values);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addAll(MultiValueMap<K, V> values) {
|
||||
for (Entry<K, List<V>> entry : values.entrySet()) {
|
||||
addAll(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set(K key, @Nullable V value) {
|
||||
// 构造list
|
||||
@ -111,13 +106,13 @@ public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V>, Serializa
|
||||
// 添加
|
||||
this.targetMap.put(key, values);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setAll(Map<K, V> values) {
|
||||
// 循环执行 set 方法
|
||||
values.forEach(this::set);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<K, V> toSingleValueMap() {
|
||||
// 返回结果定义
|
||||
@ -134,4 +129,4 @@ public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V>, Serializa
|
||||
}
|
||||
```
|
||||
|
||||
- 其他实现类也基本和这个类相同, 不做具体展开
|
||||
- 其他实现类也基本和这个类相同, 不做具体展开
|
||||
|
@ -3,35 +3,24 @@
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 相关类
|
||||
- `org.springframework.beans.PropertyValues`
|
||||
- `org.springframework.beans.PropertyValue`
|
||||
- `org.springframework.beans.MutablePropertyValues`
|
||||
|
||||
|
||||
|
||||
- `org.springframework.beans.PropertyValues`
|
||||
- `org.springframework.beans.PropertyValue`
|
||||
- `org.springframework.beans.MutablePropertyValues`
|
||||
|
||||
- 类图如下
|
||||
|
||||

|
||||
|
||||
- 在 Spring IoC 中,**非 Web 工程**,使用 xml 或者注解进行配置主要使用到的是 `PropertyValues` ,`PropertyValue` ,`MutablePropertyValues` 三个
|
||||
|
||||
其中 `PropertyValues` 是继承迭代器,具体实现在`MutablePropertyValues` 他们处理的对象是`PropertyValues`
|
||||
|
||||
- 在 Spring IoC 中,**非Web工程**,使用 xml 或者注解进行配置主要使用到的是 `PropertyValues` ,`PropertyValue` ,`MutablePropertyValues` 三个
|
||||
|
||||
其中 `PropertyValues` 是继承迭代器,具体实现在`MutablePropertyValues` 他们处理的对象是`PropertyValues`
|
||||
|
||||
关系就是这样.
|
||||
|
||||
|
||||
关系就是这样.
|
||||
|
||||
- 开始类的解析了
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## PropertyValue
|
||||
|
||||
- `org.springframework.beans.PropertyValue`
|
||||
@ -45,13 +34,9 @@
|
||||
1. name: 属性名称
|
||||
2. value: 属性值
|
||||
|
||||
对应标签`<property name="age" value="30"/>`
|
||||
|
||||
属性值一一对应填入.
|
||||
|
||||
|
||||
|
||||
对应标签`<property name="age" value="30"/>`
|
||||
|
||||
属性值一一对应填入.
|
||||
|
||||
## MutablePropertyValues
|
||||
|
||||
@ -62,8 +47,6 @@
|
||||
2. `processedProperties`: 已经处理的属性名称
|
||||
3. `converted`: 是否转换
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public class MutablePropertyValues implements PropertyValues, Serializable {
|
||||
/**
|
||||
@ -84,8 +67,6 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 构造器
|
||||
|
||||
- `MutablePropertyValues` 的一个构造器. 其他构造器的方式原理实现差不多. 核心是将构造参数转换成`PropertyValue`对象在放入`propertyValueList`中
|
||||
@ -109,16 +90,8 @@ public MutablePropertyValues(@Nullable PropertyValues original) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### PropertyValue 的构造方法
|
||||
|
||||
|
||||
|
||||
```JAVA
|
||||
public PropertyValue(PropertyValue original) {
|
||||
Assert.notNull(original, "Original must not be null");
|
||||
@ -135,16 +108,8 @@ public MutablePropertyValues(@Nullable PropertyValues original) {
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 除了最后一行是一个复杂调用. 前面几行代码都是属性赋值操作.
|
||||
- 最后一行代码会调用`AttributeAccessor`接口上的方法.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 除了最后一行是一个复杂调用. 前面几行代码都是属性赋值操作.
|
||||
- 最后一行代码会调用`AttributeAccessor`接口上的方法.
|
||||
|
||||
## AttributeAccessor
|
||||
|
||||
@ -194,16 +159,8 @@ public interface AttributeAccessor {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 回到`org.springframework.core.AttributeAccessorSupport#copyAttributesFrom`方法
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```java
|
||||
protected void copyAttributesFrom(AttributeAccessor source) {
|
||||
Assert.notNull(source, "Source must not be null");
|
||||
@ -218,13 +175,9 @@ protected void copyAttributesFrom(AttributeAccessor source) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### setAttribute
|
||||
|
||||
- 一个map操作
|
||||
- 一个 map 操作
|
||||
|
||||
```java
|
||||
@Override
|
||||
@ -239,8 +192,6 @@ public void setAttribute(String name, @Nullable Object value) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## addPropertyValue
|
||||
|
||||
- `org.springframework.beans.MutablePropertyValues#addPropertyValue(org.springframework.beans.PropertyValue)`
|
||||
@ -268,17 +219,11 @@ public void setAttribute(String name, @Nullable Object value) {
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## mergeIfRequired
|
||||
|
||||
- `org.springframework.beans.MutablePropertyValues#mergeIfRequired`
|
||||
|
||||
|
||||
|
||||
- 这段代码会取舍新老数据.
|
||||
- 这段代码会取舍新老数据.
|
||||
1. 如果是`Mergeable`类型会做合并操作
|
||||
2. 直接返回新数据
|
||||
|
||||
@ -299,9 +244,7 @@ public void setAttribute(String name, @Nullable Object value) {
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 配合测试代码,跟容易看懂.
|
||||
- 配合测试代码,跟容易看懂.
|
||||
|
||||
```java
|
||||
@Test
|
||||
@ -320,28 +263,12 @@ public void setAttribute(String name, @Nullable Object value) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Mergeable
|
||||
|
||||
|
||||
|
||||
新的接口`Mergeable`
|
||||
|
||||
- `org.springframework.beans.Mergeable`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public interface Mergeable {
|
||||
|
||||
@ -358,16 +285,10 @@ public interface Mergeable {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
- 看一下 List 怎么实现`merge`
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -388,6 +309,4 @@ public List<E> merge(@Nullable Object parent) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 在 list 视线中就是讲两个结果合并. 事实上其他的几个都是这个操作. 这里就不贴所有的代码了
|
||||
- 在 list 视线中就是讲两个结果合并. 事实上其他的几个都是这个操作. 这里就不贴所有的代码了
|
||||
|
@ -1,21 +1,11 @@
|
||||
# Spring PropertyPlaceholderHelper
|
||||
|
||||
|
||||
# Spring PropertyPlaceholderHelper
|
||||
|
||||
- 类全路径: `org.springframework.util.PropertyPlaceholderHelper`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## parseStringValue
|
||||
|
||||
- `org.springframework.util.PropertyPlaceholderHelper#parseStringValue` 这个方法是主要方法
|
||||
|
||||
|
||||
|
||||
```java
|
||||
protected String parseStringValue(
|
||||
String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {
|
||||
@ -87,11 +77,9 @@ protected String parseStringValue(
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
在这里还需要关注一个接口
|
||||
|
||||
- 占位符解析.
|
||||
- 占位符解析.
|
||||
|
||||
```java
|
||||
@FunctionalInterface
|
||||
@ -107,12 +95,8 @@ public interface PlaceholderResolver {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
占位符解析请查看: [PlaceholderResolver](PlaceholderResolver)
|
||||
|
||||
|
||||
|
||||
## findPlaceholderEndIndex
|
||||
|
||||
- 寻找结尾占位符索引
|
||||
@ -145,10 +129,3 @@ private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -3,19 +3,14 @@
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
|
||||
|
||||
## MutablePropertySources
|
||||
|
||||
- 全路径: `org.springframework.core.env.MutablePropertySources`
|
||||
- 全路径: `org.springframework.core.env.MutablePropertySources`
|
||||
|
||||
- `MutablePropertySources`类内部存储了`List<PropertySource<?>>`对象,主要是针对`List<PropertySource<?>>` 进行的操作.换句话说就是对 list 操作的实现
|
||||
|
||||
- 类注解如下
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public class MutablePropertySources implements PropertySources {
|
||||
|
||||
@ -238,10 +233,6 @@ public class MutablePropertySources implements PropertySources {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## PropertySources
|
||||
|
||||
- 类路径: `org.springframework.core.env.PropertySources`
|
||||
@ -269,7 +260,7 @@ public interface PropertySources extends Iterable<PropertySource<?>> {
|
||||
|
||||
/**
|
||||
* Return the property source with the given name, {@code null} if not found.
|
||||
* 获取 PropertySource
|
||||
* 获取 PropertySource
|
||||
* @param name the {@linkplain PropertySource#getName() name of the property source} to find
|
||||
*/
|
||||
@Nullable
|
||||
@ -278,22 +269,13 @@ public interface PropertySources extends Iterable<PropertySource<?>> {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## PropertySource
|
||||
|
||||
- 类路径: `org.springframework.core.env.PropertySource`
|
||||
|
||||
- 存有两个子类
|
||||
1. StubPropertySource
|
||||
2. ComparisonPropertySource
|
||||
3. 调用`getSource`、`containsProperty`、`getProperty` 都会直接异常
|
||||
|
||||
|
||||
2. ComparisonPropertySource 3. 调用`getSource`、`containsProperty`、`getProperty` 都会直接异常
|
||||
|
||||
```java
|
||||
public abstract class PropertySource<T> {
|
||||
@ -500,10 +482,6 @@ public abstract class PropertySource<T> {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
类图
|
||||
|
||||

|
||||

|
||||
|
@ -1,8 +1,7 @@
|
||||
# Spring SystemPropertyUtils
|
||||
|
||||
- spring 中获取系统属性的工具类
|
||||
|
||||
|
||||
|
||||
- 内部属性
|
||||
|
||||
```java
|
||||
@ -39,19 +38,13 @@ private static final PropertyPlaceholderHelper nonStrictHelper =
|
||||
new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, true);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## resolvePlaceholders
|
||||
|
||||
- 解析属性
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
时序图因为有递归所以看着有点长, 其核心方法最后会指向 PlaceholderResolver
|
||||
时序图因为有递归所以看着有点长, 其核心方法最后会指向 PlaceholderResolver
|
||||
|
||||
通过 PlaceholderResolver 获取属性值
|
||||
|
||||
@ -87,4 +80,4 @@ private static class SystemPropertyPlaceholderResolver implements PropertyPlaceh
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -4,9 +4,9 @@
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
- 源码路径: `org.springframework.jms.annotation.EnableJms`
|
||||
|
||||
|
||||
- `org.springframework.web.servlet.HandlerMapping`
|
||||
- HandlerMapping 处理映射关系, 通过请求转换成对象`HandlerExecutionChain`
|
||||
|
||||
```java
|
||||
public interface HandlerMapping {
|
||||
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
|
||||
@ -14,14 +14,8 @@ public interface HandlerMapping {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Override
|
||||
@Nullable
|
||||
@ -62,8 +56,6 @@ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
- `getHandlerInternal`方法是一个抽象方法
|
||||
|
||||
```JAVA
|
||||
@ -75,14 +67,8 @@ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 先看`org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal`方法是怎么一回事.
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Override
|
||||
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
|
||||
@ -105,13 +91,7 @@ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## UrlPathHelper
|
||||
## UrlPathHelper
|
||||
|
||||
- 全路径:`org.springframework.web.util.UrlPathHelper`
|
||||
|
||||
@ -122,28 +102,22 @@ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws
|
||||
* 是否全路径标记
|
||||
*/
|
||||
private boolean alwaysUseFullPath = false;
|
||||
|
||||
|
||||
/**
|
||||
* 是否需要 decode
|
||||
*/
|
||||
private boolean urlDecode = true;
|
||||
|
||||
|
||||
private boolean removeSemicolonContent = true;
|
||||
|
||||
|
||||
/**
|
||||
* 默认的encoding编码格式
|
||||
*/
|
||||
private String defaultEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### getPathWithinApplication
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public String getPathWithinApplication(HttpServletRequest request) {
|
||||
// 获取 context path
|
||||
@ -163,19 +137,15 @@ public String getPathWithinApplication(HttpServletRequest request) {
|
||||
|
||||
1. 从 request 中获取 context-path
|
||||
1. 从属性中直接获取
|
||||
2. 从request中调用 getContextPath 获取
|
||||
2. 从 request 中调用 getContextPath 获取
|
||||
3. 判断是否是**`/`**
|
||||
4. decode request string
|
||||
4. decode request string
|
||||
2. 从 request 中虎丘 request-uri
|
||||
1. 从属性中获取
|
||||
2. 从 request 中调用 getRequestURI 获取
|
||||
3. decode
|
||||
3. decode
|
||||
3. 获取剩余路径
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### getContextPath
|
||||
|
||||
- 获取 context-path 地址
|
||||
@ -196,10 +166,6 @@ public String getContextPath(HttpServletRequest request) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### decodeRequestString
|
||||
|
||||
- 判断是否需要编码, 需要编码就做编码操作,不需要就直接返回
|
||||
@ -215,12 +181,6 @@ public String decodeRequestString(HttpServletRequest request, String source) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### decodeInternal
|
||||
|
||||
- 编码方法
|
||||
@ -245,16 +205,10 @@ private String decodeInternal(HttpServletRequest request, String source) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### determineEncoding
|
||||
|
||||
- 确认编码
|
||||
|
||||
|
||||
|
||||
```java
|
||||
protected String determineEncoding(HttpServletRequest request) {
|
||||
// 从 request 中获取编码方式
|
||||
@ -267,10 +221,6 @@ protected String determineEncoding(HttpServletRequest request) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### getRequestUri
|
||||
|
||||
- 获取 uri 地址
|
||||
@ -289,10 +239,6 @@ protected String determineEncoding(HttpServletRequest request) {
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### decodeAndCleanUriString
|
||||
|
||||
- 编码和清理数据
|
||||
@ -309,12 +255,6 @@ private String decodeAndCleanUriString(HttpServletRequest request, String uri) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### shouldRemoveTrailingServletPathSlash
|
||||
|
||||
- 是否删除 servlet path 后的斜杠
|
||||
@ -359,10 +299,6 @@ private boolean shouldRemoveTrailingServletPathSlash(HttpServletRequest request)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### decodeMatrixVariables
|
||||
|
||||
- 编码修改方法
|
||||
@ -391,8 +327,6 @@ public MultiValueMap<String, String> decodeMatrixVariables(
|
||||
|
||||
- 与这个方法对应的还有`decodePathVariables`
|
||||
|
||||
|
||||
|
||||
### decodePathVariables
|
||||
|
||||
```java
|
||||
@ -403,39 +337,27 @@ public Map<String, String> decodePathVariables(HttpServletRequest request, Map<S
|
||||
}
|
||||
else {
|
||||
Map<String, String> decodedVars = new LinkedHashMap<>(vars.size());
|
||||
// 虚幻 decoding
|
||||
// 虚幻 decoding
|
||||
vars.forEach((key, value) -> decodedVars.put(key, decodeInternal(request, value)));
|
||||
return decodedVars;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 回到`org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal`
|
||||
|
||||
```JAVA
|
||||
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 设置属性上锁开锁就不具体展开了.
|
||||
|
||||
|
||||
|
||||
## lookupHandlerMethod
|
||||
|
||||
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod` 方法
|
||||
|
||||
|
||||
|
||||
- 第一部分
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
|
||||
@ -452,14 +374,12 @@ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletReques
|
||||
// 添加匹配映射
|
||||
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
|
||||
}
|
||||
|
||||
|
||||
//...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 创建一个匹配list,将匹配结果放入
|
||||
- 创建一个匹配 list,将匹配结果放入
|
||||
|
||||
```
|
||||
List<Match> matches = new ArrayList<>();
|
||||
@ -478,7 +398,7 @@ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletReques
|
||||
}
|
||||
```
|
||||
|
||||
urlLookup 是`MultiValueMap`接口.
|
||||
urlLookup 是`MultiValueMap`接口.
|
||||
|
||||
key:url value:mapping
|
||||
|
||||
@ -511,8 +431,6 @@ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletReques
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
- `getMatchingMapping` 方法是一个抽象方法
|
||||
|
||||
```java
|
||||
@ -528,16 +446,8 @@ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletReques
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 第二部分
|
||||
|
||||
|
||||
|
||||
```java
|
||||
if (!matches.isEmpty()) {
|
||||
// 比较对象
|
||||
@ -573,10 +483,6 @@ else {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 一行行开始分析
|
||||
|
||||
```java
|
||||
@ -603,8 +509,6 @@ protected abstract Comparator<T> getMappingComparator(HttpServletRequest request
|
||||
- 执行完成比较方法后创建对象`MatchComparator`
|
||||
- 对象创建后进行排序,排序后取出第一个元素作为后续操作的基准对象
|
||||
|
||||
|
||||
|
||||
```java
|
||||
// 排序
|
||||
matches.sort(comparator);
|
||||
@ -612,10 +516,6 @@ matches.sort(comparator);
|
||||
Match bestMatch = matches.get(0);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```java
|
||||
if (matches.size() > 1) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
@ -643,12 +543,8 @@ if (matches.size() > 1) {
|
||||
|
||||
- 取出第一个元素和第二个元素进行比较. 如果两个 match 相同, 出现异常
|
||||
|
||||
|
||||
|
||||
最后两个方法
|
||||
|
||||
|
||||
|
||||
```java
|
||||
// 设置属性
|
||||
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
|
||||
@ -662,8 +558,6 @@ else {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
- `handleMatch`
|
||||
|
||||
```java
|
||||
@ -678,8 +572,6 @@ else {
|
||||
|
||||
- `org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleMatch`
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Override
|
||||
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
|
||||
@ -723,10 +615,6 @@ protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServl
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- `handleNoMatch` 也是同类型操作
|
||||
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#handleNoMatch`
|
||||
- `org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleNoMatch`
|
||||
@ -783,10 +671,3 @@ protected HandlerMethod handleNoMatch(
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -5,44 +5,42 @@
|
||||
- 源码路径: `org.springframework.jms.annotation.EnableJms`
|
||||
|
||||
- 类全路径
|
||||
|
||||
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry`
|
||||
|
||||
- 基本属性
|
||||
|
||||
```java
|
||||
class MappingRegistry {
|
||||
|
||||
|
||||
/**
|
||||
* key:mapping
|
||||
* value: mapping registration
|
||||
*/
|
||||
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* key: mapping
|
||||
* value: handlerMethod
|
||||
*/
|
||||
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* key: url
|
||||
* value: list mapping
|
||||
*/
|
||||
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* key: name
|
||||
* value: handler method
|
||||
*/
|
||||
private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* key:handler method
|
||||
* value: 跨域配置
|
||||
*/
|
||||
private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* 读写锁
|
||||
*/
|
||||
@ -50,11 +48,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 写一个简单的controller 来进行解析
|
||||
- 写一个简单的 controller 来进行解析
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@ -67,8 +61,6 @@ public class DemoController {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 前置链路追踪
|
||||
|
||||
- `org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#registerHandlerMethod`
|
||||
@ -96,10 +88,6 @@ public class DemoController {
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## createHandlerMethod
|
||||
|
||||
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#createHandlerMethod`
|
||||
@ -116,23 +104,15 @@ protected HandlerMethod createHandlerMethod(Object handler, Method method) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- HandlerMethod 构造函数
|
||||
|
||||
```java
|
||||
public HandlerMethod(String beanName, BeanFactory beanFactory, Method method){}
|
||||
|
||||
|
||||
public HandlerMethod(Object bean, Method method) {}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## HandlerMethod
|
||||
## HandlerMethod
|
||||
|
||||
- 成员变量
|
||||
|
||||
@ -172,10 +152,6 @@ public class HandlerMethod {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## validateMethodMapping
|
||||
|
||||
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#validateMethodMapping`
|
||||
@ -197,8 +173,6 @@ private void validateMethodMapping(HandlerMethod handlerMethod, T mapping) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## getDirectUrls
|
||||
|
||||
- 找到 mapping 匹配的 url
|
||||
@ -219,8 +193,6 @@ private List<String> getDirectUrls(T mapping) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## handlerMethod 和 name 绑定
|
||||
|
||||
```java
|
||||
@ -236,8 +208,6 @@ if (getNamingStrategy() != null) {
|
||||
|
||||
- `org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMethodMappingNamingStrategy#getName`
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Override
|
||||
public String getName(HandlerMethod handlerMethod, RequestMappingInfo mapping) {
|
||||
@ -259,16 +229,10 @@ public String getName(HandlerMethod handlerMethod, RequestMappingInfo mapping) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## initCorsConfiguration
|
||||
|
||||
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initCorsConfiguration`
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Override
|
||||
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) {
|
||||
@ -301,12 +265,6 @@ protected CorsConfiguration initCorsConfiguration(Object handler, Method method,
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## unregister
|
||||
|
||||
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#unregister`
|
||||
@ -344,4 +302,4 @@ public void unregister(T mapping) {
|
||||
this.readWriteLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -326,7 +326,6 @@ public @interface EnableConfigurationProperties {
|
||||
```yml
|
||||
server:
|
||||
port: 9999
|
||||
|
||||
```
|
||||
|
||||
- 具体方法: `org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#bind`
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
@ -1 +1 @@
|
||||
努力编写中...
|
||||
努力编写中...
|
||||
|
166
index.html
166
index.html
@ -1,81 +1,109 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>读尽天下源码,心中自然无码</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="keywords" content="doc,docs,doocs,documentation,github,gitee,source-code-hunter,AmyliaY">
|
||||
<meta name="description" content="读尽天下源码,心中自然无码,《源码猎人》项目维护者:云之君">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/vue.css">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify-dark-mode@0.6.1/dist/style.css" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="images/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="images/favicon-16x16.png">
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>分类
|
||||
<ul>
|
||||
<li><a href="#/?id=spring-系列">Spring系列</a></li>
|
||||
<li><a href="#/?id=mybatis">Mybatis</a></li>
|
||||
<li><a href="#/?id=netty">Netty</a></li>
|
||||
<li><a href="#/?id=tomcat">Tomcat</a></li>
|
||||
<li><a href="#/?id=番外篇(jdk-18)">JDK 1.8</a></li>
|
||||
<li><a href="#/?id=学习心得">学习心得</a></li>
|
||||
</ul>
|
||||
<meta
|
||||
name="keywords"
|
||||
content="doc,docs,doocs,documentation,github,gitee,source-code-hunter,AmyliaY"
|
||||
/>
|
||||
<meta
|
||||
name="description"
|
||||
content="读尽天下源码,心中自然无码,《源码猎人》项目维护者:云之君"
|
||||
/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="//cdn.jsdelivr.net/npm/docsify/lib/themes/vue.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="//cdn.jsdelivr.net/npm/docsify-dark-mode@0.6.1/dist/style.css"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="images/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="images/favicon-16x16.png"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
分类
|
||||
<ul>
|
||||
<li><a href="#/?id=spring-系列">Spring系列</a></li>
|
||||
<li><a href="#/?id=mybatis">Mybatis</a></li>
|
||||
<li><a href="#/?id=netty">Netty</a></li>
|
||||
<li><a href="#/?id=tomcat">Tomcat</a></li>
|
||||
<li><a href="#/?id=番外篇(jdk-18)">JDK 1.8</a></li>
|
||||
<li><a href="#/?id=学习心得">学习心得</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>页面
|
||||
<ul>
|
||||
<li><a href="#/README">首页</a></li>
|
||||
<li><a href="https://github.com/doocs" target="_blank">Doocs</a></li>
|
||||
<li><a href="https://github.com/AmyliaY" target="_blank">Author</a></li>
|
||||
</ul>
|
||||
<li>
|
||||
页面
|
||||
<ul>
|
||||
<li><a href="#/README">首页</a></li>
|
||||
<li>
|
||||
<a href="https://github.com/doocs" target="_blank">Doocs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/AmyliaY" target="_blank">Author</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
<div id="app">本系列知识由 Doocs 开源社区总结发布</div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: 'source-code-hunter',
|
||||
</ul>
|
||||
</nav>
|
||||
<div id="app">本系列知识由 Doocs 开源社区总结发布</div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: "source-code-hunter",
|
||||
maxLevel: 3,
|
||||
auto2top: true,
|
||||
search: [
|
||||
'/'
|
||||
],
|
||||
search: ["/"],
|
||||
darkMode: {
|
||||
light: {
|
||||
toggleBtnBg: '#42b983'
|
||||
}
|
||||
light: {
|
||||
toggleBtnBg: "#42b983",
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
function (hook) {
|
||||
var footer = [
|
||||
'<hr/>',
|
||||
'<footer>',
|
||||
'<span>Copyright © 2018-2020 <a href="https://github.com/doocs" target="_blank">Doocs</a>. All rights reserved.',
|
||||
'</footer>'
|
||||
].join('')
|
||||
function (hook) {
|
||||
var footer = [
|
||||
"<hr/>",
|
||||
"<footer>",
|
||||
'<span>Copyright © 2018-2020 <a href="https://github.com/doocs" target="_blank">Doocs</a>. All rights reserved.',
|
||||
"</footer>",
|
||||
].join("");
|
||||
|
||||
hook.afterEach(function (html) {
|
||||
return html + footer
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-c.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-cpp.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-json.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-java.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-python.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-copy-code"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/emoji.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-dark-mode@0.6.1/dist/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
hook.afterEach(function (html) {
|
||||
return html + footer;
|
||||
});
|
||||
},
|
||||
],
|
||||
};
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-c.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-cpp.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-json.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-java.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-python.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-copy-code"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/emoji.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-dark-mode@0.6.1/dist/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
x
Reference in New Issue
Block a user