docs: prettify code

pull/76/head
yanglbme 5 years ago committed by GitHub Action
parent e909ca2b88
commit f1bab50f64

@ -1,4 +1,5 @@
# GenericTokenParser # GenericTokenParser
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读工程: [SourceHot-Mybatis](https://github.com/SourceHot/mybatis-read.git) - 源码阅读工程: [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.ParameterMappingTokenHandler`
- 具体类`org.apache.ibatis.builder.SqlSourceBuilder` - 具体类`org.apache.ibatis.builder.SqlSourceBuilder`
```java ```java
/** /**
* ? 的来源 * ? 的来源
@ -137,6 +138,7 @@ public class GenericTokenParser {
} }
``` ```
```java ```java
/** /**
* sql 参数类型 返回值 * sql 参数类型 返回值

@ -1,10 +1,11 @@
## Netty 的线程模型 ## Netty 的线程模型
Netty线程模型 的设计,也是基于 Reactor模型尽管不同的 NIO框架 对于 Reactor模式 的实现存在差异,但本质上还是遵循了 Reactor 的基础线程模型。
Netty 线程模型 的设计,也是基于 Reactor 模型,尽管不同的 NIO 框架 对于 Reactor 模式 的实现存在差异,但本质上还是遵循了 Reactor 的基础线程模型。
#### Reactor 单线程模型 #### Reactor 单线程模型
Reactor 单线程模型,是指所有的 I/O 操作 都在同一个 NIO 线程 上完成。NIO 线程 的职责如下。 Reactor 单线程模型,是指所有的 I/O 操作 都在同一个 NIO 线程 上完成。NIO 线程 的职责如下。
1. 作为 NIO 服务端,接收客户端的 TCP 连接; 1. 作为 NIO 服务端,接收客户端的 TCP 连接;
2. 作为 NIO 客户端,向服务端发起 TCP 连接; 2. 作为 NIO 客户端,向服务端发起 TCP 连接;
3. 读取通信对端的请求或者应答消息; 3. 读取通信对端的请求或者应答消息;
@ -13,7 +14,9 @@ Reactor单线程模型是指所有的 I/O操作 都在同一个 NIO线程 上
理论上一个 NIO 线程 可以独立处理所有 I/O 操作。例如,通过 Acceptor 类 接收客户端的 TCP 连接,链路建立成功后,通过 Dispatch 轮询事件就绪的 Channel将事件分发到指定的 Handler 上进行事件处理。小容量应用场景下,可以使用单线程模型。但对于高负载、大并发的应用场景并不合用。 理论上一个 NIO 线程 可以独立处理所有 I/O 操作。例如,通过 Acceptor 类 接收客户端的 TCP 连接,链路建立成功后,通过 Dispatch 轮询事件就绪的 Channel将事件分发到指定的 Handler 上进行事件处理。小容量应用场景下,可以使用单线程模型。但对于高负载、大并发的应用场景并不合用。
#### Reactor 多线程模型 #### Reactor 多线程模型
Rector 多线程模型 与 单线程模型 最大的区别就是有一组 NIO 线程 来处理 I/O 操作Reactor 多线程模型 的特点如下。 Rector 多线程模型 与 单线程模型 最大的区别就是有一组 NIO 线程 来处理 I/O 操作Reactor 多线程模型 的特点如下。
1. 有专门一个 NIO 线程 (Acceptor 线程) 用于监听服务端,接收客户端的 TCP 连接请求。 1. 有专门一个 NIO 线程 (Acceptor 线程) 用于监听服务端,接收客户端的 TCP 连接请求。
2. 网络 IO 操作 由一个 NIO 线程池 负责,由这些 NIO 线程 负责消息的 读取、解码、编码、发送。 2. 网络 IO 操作 由一个 NIO 线程池 负责,由这些 NIO 线程 负责消息的 读取、解码、编码、发送。
3. 一个 NIO 线程 可以同时处理 N 条链路,但是一个链路只对应一个 NIO 线程,防止发生并发操作问题。 3. 一个 NIO 线程 可以同时处理 N 条链路,但是一个链路只对应一个 NIO 线程,防止发生并发操作问题。
@ -21,11 +24,13 @@ Rector多线程模型 与 单线程模型 最大的区别就是有一组 NIO线
Reactor 多线程模型 可以满足大部分场景的需求。但对于 百万级超高并发 或 服务端需要对客户端进行安全认证,但认证非常消耗资源。在这类场景下,单独一个 Acceptor 线程 可能会处理不过来,成为系统的性能瓶颈。 Reactor 多线程模型 可以满足大部分场景的需求。但对于 百万级超高并发 或 服务端需要对客户端进行安全认证,但认证非常消耗资源。在这类场景下,单独一个 Acceptor 线程 可能会处理不过来,成为系统的性能瓶颈。
#### Reactor 主从多线程模型 #### Reactor 主从多线程模型
主从 Reactor 多线程模型的特点是,服务端用于接收客户端连接的是一个独立的 NIO 线程池。**Acceptor 线程 与客户端建立 TCP 连接 后,将新的 SocketChannel 注册到 NIO 线程池 的某个 NIO 线程 上,由该 NIO 线程 负责轮询 SocketChannel 上的 IO 事件,并进行事件处理**。 主从 Reactor 多线程模型的特点是,服务端用于接收客户端连接的是一个独立的 NIO 线程池。**Acceptor 线程 与客户端建立 TCP 连接 后,将新的 SocketChannel 注册到 NIO 线程池 的某个 NIO 线程 上,由该 NIO 线程 负责轮询 SocketChannel 上的 IO 事件,并进行事件处理**。
利用 主从多线程模型,可以解决一个服务端监听线程无法有效处理所有客户端连接的性能不足问题。在 Netty 的官方 Demo 中,也是推荐使用该线程模型。 利用 主从多线程模型,可以解决一个服务端监听线程无法有效处理所有客户端连接的性能不足问题。在 Netty 的官方 Demo 中,也是推荐使用该线程模型。
#### Netty 多线程编程最佳实践 #### Netty 多线程编程最佳实践
1. **如果业务逻辑比较简单,并且没有 数据库操作、线程阻塞的磁盘操作、网路操作等,可以直接在 NIO 线程 上完成业务逻辑编排,不需要切换到用户线程;** 1. **如果业务逻辑比较简单,并且没有 数据库操作、线程阻塞的磁盘操作、网路操作等,可以直接在 NIO 线程 上完成业务逻辑编排,不需要切换到用户线程;**
2. **如果业务逻辑比较复杂,不要在 NIO 线程 上完成,建议将解码后的 POJO 消息 封装成 Task分发到 业务线程池 中由业务线程执行,以保证 NIO 线程 尽快被释放,处理其他的 I/O 操作。** 2. **如果业务逻辑比较复杂,不要在 NIO 线程 上完成,建议将解码后的 POJO 消息 封装成 Task分发到 业务线程池 中由业务线程执行,以保证 NIO 线程 尽快被释放,处理其他的 I/O 操作。**
3. **由于用户场景不同,对于一些复杂系统,很难根据 理论公式 计算出最优线程配置,只能是 结合公式给出一个相对合理的范围,然后对范围内的数据进行性能测试,选择相对最优配置。** 3. **由于用户场景不同,对于一些复杂系统,很难根据 理论公式 计算出最优线程配置,只能是 结合公式给出一个相对合理的范围,然后对范围内的数据进行性能测试,选择相对最优配置。**

@ -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 等待下一轮的执行。 在 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 的集合 - chunk: 一个 chunk 是一组 page 的集合
- 在 PoolChunk 中chunkSize 的大小是 `2^maxOrder * pageSize`,其中 2^maxOrder 是 PoolChunk 中的完全二叉树叶子结点的数量pageSize 则是单个 page 的大小。 - 在 PoolChunk 中chunkSize 的大小是 `2^maxOrder * pageSize`,其中 2^maxOrder 是 PoolChunk 中的完全二叉树叶子结点的数量pageSize 则是单个 page 的大小。
综合如上所述,举一个数字上的例子,默认情况下,单个 Page 的大小为 8192也就是 8kbmaxOrder 默认情况下是 11因此在这个情况下 PoolChunk 中的二叉树的叶子节点数量是 2048chunkSize 的大小则是 2048*8kb 为 16M。 综合如上所述,举一个数字上的例子,默认情况下,单个 Page 的大小为 8192也就是 8kbmaxOrder 默认情况下是 11因此在这个情况下 PoolChunk 中的二叉树的叶子节点数量是 2048chunkSize 的大小则是 2048\*8kb 为 16M。
## PoolChunk 的内部完全二叉树结构 ## PoolChunk 的内部完全二叉树结构

@ -1,4 +1,5 @@
# Spring PlaceholderResolver # Spring PlaceholderResolver
- 类全路径: `org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver` - 类全路径: `org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver`
- 类作用将占位符中的内容替换成属性值. - 类作用将占位符中的内容替换成属性值.

@ -2,7 +2,6 @@
- 类全路径: `org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.PropertyPlaceholderConfigurerResolver` - 类全路径: `org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.PropertyPlaceholderConfigurerResolver`
- 这个类是从 Properties 中获取属性 - 这个类是从 Properties 中获取属性
```java ```java
@ -45,7 +44,6 @@
``` ```
```java ```java
@Nullable @Nullable
protected String resolvePlaceholder(String placeholder, Properties props) { protected String resolvePlaceholder(String placeholder, Properties props) {
@ -53,7 +51,6 @@
} }
``` ```
```java ```java
@Nullable @Nullable
protected String resolveSystemProperty(String key) { protected String resolveSystemProperty(String key) {

@ -1,6 +1,5 @@
# Spring ServletContextPlaceholderResolver # Spring ServletContextPlaceholderResolver
- 类全路径: `org.springframework.web.util.ServletContextPropertyUtils.ServletContextPlaceholderResolver` - 类全路径: `org.springframework.web.util.ServletContextPropertyUtils.ServletContextPlaceholderResolver`
```java ```java

@ -2,7 +2,6 @@
- 类全路径: `org.springframework.util.SystemPropertyUtils.SystemPropertyPlaceholderResolver` - 类全路径: `org.springframework.util.SystemPropertyUtils.SystemPropertyPlaceholderResolver`
```java ```java
private static class SystemPropertyPlaceholderResolver implements PropertyPlaceholderHelper.PlaceholderResolver { private static class SystemPropertyPlaceholderResolver implements PropertyPlaceholderHelper.PlaceholderResolver {

@ -3,14 +3,9 @@
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 类全路径: `org.springframework.core.env.CommandLinePropertySource` - 类全路径: `org.springframework.core.env.CommandLinePropertySource`
- 作用: 用来存储命令行参数 - 作用: 用来存储命令行参数
```java ```java
public abstract class CommandLinePropertySource<T> extends EnumerablePropertySource<T> { public abstract class CommandLinePropertySource<T> extends EnumerablePropertySource<T> {
@ -93,10 +88,6 @@ public abstract class CommandLinePropertySource<T> extends EnumerablePropertySou
} }
``` ```
## getOptionValues ## getOptionValues
```java ```java
@ -120,8 +111,6 @@ public abstract class CommandLinePropertySource<T> extends EnumerablePropertySou
protected abstract List<String> getOptionValues(String name); protected abstract List<String> getOptionValues(String name);
``` ```
阅读注释可以知道该方法可以获取命令行参数的列表. 阅读注释可以知道该方法可以获取命令行参数的列表.
- 如 `--foo`作为开头当输入命令行为 `--foo=bar --foo=baz` 在输入参数名称 `foo` 会得到数据`bar,baz` - 如 `--foo`作为开头当输入命令行为 `--foo=bar --foo=baz` 在输入参数名称 `foo` 会得到数据`bar,baz`

@ -3,7 +3,6 @@
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 整体代码如下. - 整体代码如下.
- 下面几个调用方法会直接抛出异常 - 下面几个调用方法会直接抛出异常
1. getSource 1. getSource

@ -1,11 +1,12 @@
# Spring CompositePropertySource # Spring CompositePropertySource
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 全路径: `org.springframework.core.env.CompositePropertySource` - 全路径: `org.springframework.core.env.CompositePropertySource`
- 整体代码如下 - 整体代码如下
```java ```java
public class CompositePropertySource extends EnumerablePropertySource<Object> { public class CompositePropertySource extends EnumerablePropertySource<Object> {

@ -9,7 +9,9 @@
```java ```java
public abstract String[] getPropertyNames(); public abstract String[] getPropertyNames();
``` ```
- 整体代码如下 - 整体代码如下
```java ```java
public abstract class EnumerablePropertySource<T> extends PropertySource<T> { public abstract class EnumerablePropertySource<T> extends PropertySource<T> {

@ -3,11 +3,9 @@
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 类全路径: `org.springframework.core.env.MapPropertySource` - 类全路径: `org.springframework.core.env.MapPropertySource`
- 内部数据结构是一个`Map<String,Object>` - 内部数据结构是一个`Map<String,Object>`
这是一个对 map 的操作. 这是一个对 map 的操作.
- 整体代码如下. - 整体代码如下.
```java ```java

@ -1,16 +1,10 @@
# Spring MockPropertySource # Spring MockPropertySource
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 内部 source 是 Properties 类型 - 内部 source 是 Properties 类型
## withProperty ## withProperty
- 设置属性名称和属性值 - 设置属性名称和属性值
@ -22,10 +16,6 @@ public MockPropertySource withProperty(String name, Object value) {
} }
``` ```
## setProperty ## setProperty
```java ```java
@ -34,14 +24,8 @@ public void setProperty(String name, Object value) {
} }
``` ```
## 完整代码 ## 完整代码
```java ```java
public class MockPropertySource extends PropertiesPropertySource { public class MockPropertySource extends PropertiesPropertySource {

@ -1,12 +1,10 @@
# Spring PropertiesPropertySource # Spring PropertiesPropertySource
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 全路径: `org.springframework.core.env.PropertiesPropertySource` - 全路径: `org.springframework.core.env.PropertiesPropertySource`
- Properties 是 map 结构。可以做类型转换. - Properties 是 map 结构。可以做类型转换.
- getPropertyNames 就转换成了父类 MapPropertySource 的方法了 - getPropertyNames 就转换成了父类 MapPropertySource 的方法了
- map.keySet() - map.keySet()

@ -1,18 +1,12 @@
# Spring ResourcePropertySource # Spring ResourcePropertySource
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 全路径: `org.springframework.core.io.support.ResourcePropertySource` - 全路径: `org.springframework.core.io.support.ResourcePropertySource`
- source 依然是 map 结构 - source 依然是 map 结构
## getNameForResource ## getNameForResource
```java ```java
@ -27,10 +21,6 @@ private static String getNameForResource(Resource resource) {
} }
``` ```
## withName ## withName
- 创建 ResourcePropertySource 对象, 根据 name 属性 - 创建 ResourcePropertySource 对象, 根据 name 属性
@ -56,10 +46,6 @@ public ResourcePropertySource withName(String name) {
} }
``` ```
## 构造函数 ## 构造函数
- 通过 location 字符串读取 resource - 通过 location 字符串读取 resource
@ -71,8 +57,6 @@ public ResourcePropertySource(String name, String location, ClassLoader classLoa
} }
``` ```
- 读取 resource 信息进行存储 - 读取 resource 信息进行存储
```java ```java
@ -85,8 +69,6 @@ public ResourcePropertySource(String name, EncodedResource resource) throws IOEx
} }
``` ```
## 完整代码 ## 完整代码
```java ```java

@ -3,11 +3,9 @@
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 类全路径: `org.springframework.web.context.support.ServletConfigPropertySource` - 类全路径: `org.springframework.web.context.support.ServletConfigPropertySource`
- 内部数据结构是 `ServletConfig` - 内部数据结构是 `ServletConfig`
- 整体代码如下 - 整体代码如下
```java ```java

@ -1,16 +1,12 @@
# Spring ServletContextPropertySource # Spring ServletContextPropertySource
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 类全路径: `org.springframework.web.context.support.ServletContextPropertySource` - 类全路径: `org.springframework.web.context.support.ServletContextPropertySource`
- 内部数据结构是 ServletContext 接口 - 内部数据结构是 ServletContext 接口
- 整体代码如下. - 整体代码如下.
```java ```java
public class ServletContextPropertySource extends EnumerablePropertySource<ServletContext> { public class ServletContextPropertySource extends EnumerablePropertySource<ServletContext> {

@ -1,15 +1,13 @@
# Spring SimpleCommandLineArgsParser # Spring SimpleCommandLineArgsParser
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 类全路径: `org.springframework.core.env.SimpleCommandLineArgsParser - 类全路径: `org.springframework.core.env.SimpleCommandLineArgsParser
- 类作用: 将命令行参数解析成 `org.springframework.core.env.CommandLineArgs` - 类作用: 将命令行参数解析成 `org.springframework.core.env.CommandLineArgs`
- 完整代码如下. - 完整代码如下.
```java ```java
class SimpleCommandLineArgsParser { class SimpleCommandLineArgsParser {

@ -2,20 +2,12 @@
- 全路径: `org.springframework.core.env.SimpleCommandLinePropertySource` - 全路径: `org.springframework.core.env.SimpleCommandLinePropertySource`
```java ```java
public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {} public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {}
``` ```
- SimpleCommandLinePropertySource 的 source 类型是 CommandLineArgs 具体解释请看下面分析 - SimpleCommandLinePropertySource 的 source 类型是 CommandLineArgs 具体解释请看下面分析
## CommandLineArgs ## CommandLineArgs
两个内部属性 两个内部属性
@ -50,8 +42,6 @@ public void addOptionArg(String optionName, @Nullable String optionValue) {
} }
``` ```
### getOptionNames ### getOptionNames
- 获取选项参数列表 - 获取选项参数列表
@ -62,14 +52,8 @@ public Set<String> getOptionNames() {
} }
``` ```
- 其他方法不具体描述了,各位可以查看下面的代码 - 其他方法不具体描述了,各位可以查看下面的代码
```java ```java
class CommandLineArgs { class CommandLineArgs {
@ -142,14 +126,8 @@ class CommandLineArgs {
} }
``` ```
在了解 CommandLineArgs 类后再来看 SimpleCommandLinePropertySource 会相对容易. 内部的几个方法就是调用 CommandLineArgs 所提供的方法 在了解 CommandLineArgs 类后再来看 SimpleCommandLinePropertySource 会相对容易. 内部的几个方法就是调用 CommandLineArgs 所提供的方法
```java ```java
@Override @Override
public String[] getPropertyNames() { public String[] getPropertyNames() {
@ -172,4 +150,3 @@ protected List<String> getNonOptionArgs() {
return this.source.getNonOptionArgs(); return this.source.getNonOptionArgs();
} }
``` ```

@ -3,8 +3,6 @@
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 整体代码如下. - 整体代码如下.
- 通过 StubPropertySource 的 getProperty 方法永远返回 null - 通过 StubPropertySource 的 getProperty 方法永远返回 null

@ -1,12 +1,11 @@
# Spring BeanDefinitionParserDelegate # Spring BeanDefinitionParserDelegate
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 全路径`org.springframework.beans.factory.xml.BeanDefinitionParserDelegate` - 全路径`org.springframework.beans.factory.xml.BeanDefinitionParserDelegate`
- 解析 xml 中标签的委托类 - 解析 xml 中标签的委托类
- 在这个类中定义常量如下,为后续解析提供帮助 - 在这个类中定义常量如下,为后续解析提供帮助
```java ```java
@ -147,18 +146,10 @@
private static final String SINGLETON_ATTRIBUTE = "singleton"; private static final String SINGLETON_ATTRIBUTE = "singleton";
``` ```
## populateDefaults ## populateDefaults
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#populateDefaults`方法解析属性赋值给`DocumentDefaultsDefinition`对象 - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#populateDefaults`方法解析属性赋值给`DocumentDefaultsDefinition`对象
- 代码逻辑如下 - 代码逻辑如下
1. 读取属性 1. 读取属性
2. 判断是否默认值 2. 判断是否默认值
@ -215,8 +206,6 @@ protected void populateDefaults(DocumentDefaultsDefinition defaults, @Nullable D
} }
``` ```
### DocumentDefaultsDefinition ### DocumentDefaultsDefinition
- 全路径:`org.springframework.beans.factory.xml.DocumentDefaultsDefinition` - 全路径:`org.springframework.beans.factory.xml.DocumentDefaultsDefinition`
@ -266,12 +255,6 @@ public class DocumentDefaultsDefinition implements DefaultsDefinition {
} }
``` ```
## checkNameUniqueness ## checkNameUniqueness
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#checkNameUniqueness` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#checkNameUniqueness`
@ -309,10 +292,6 @@ protected void checkNameUniqueness(String beanName, List<String> aliases, Elemen
} }
``` ```
## createBeanDefinition ## createBeanDefinition
- `org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition` - `org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition`
@ -343,29 +322,15 @@ public static AbstractBeanDefinition createBeanDefinition(
} }
``` ```
## parseBeanDefinitionElement ## parseBeanDefinitionElement
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)`
- 该方法用来解析 `<bean/>` 标签信息 - 该方法用来解析 `<bean/>` 标签信息
## ##
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, java.lang.String, org.springframework.beans.factory.config.BeanDefinition)` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, java.lang.String, org.springframework.beans.factory.config.BeanDefinition)`
```java ```java
@Nullable @Nullable
public AbstractBeanDefinition parseBeanDefinitionElement( public AbstractBeanDefinition parseBeanDefinitionElement(
@ -432,12 +397,8 @@ public AbstractBeanDefinition parseBeanDefinitionElement(
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionAttributes` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionAttributes`
- 将 xml 标签的数据读取到内存中设置给`AbstractBeanDefinition` - 将 xml 标签的数据读取到内存中设置给`AbstractBeanDefinition`
```JAVA ```JAVA
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) { @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
@ -539,14 +500,8 @@ public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String
} }
``` ```
### parseMetaElements ### parseMetaElements
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseMetaElements` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseMetaElements`
- 设置元数据. - 设置元数据.
@ -578,8 +533,6 @@ public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attribu
} }
``` ```
使用案例 使用案例
```xml ```xml
@ -588,8 +541,6 @@ public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attribu
</bean> </bean>
``` ```
```java ```java
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/beans/spring-lookup-method.xml"); 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); System.out.println(attribute);
``` ```
### parseLookupOverrideSubElements ### parseLookupOverrideSubElements
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseLookupOverrideSubElements` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseLookupOverrideSubElements`
@ -609,8 +558,6 @@ System.out.println(attribute);
`lookup-method` `lookup-method`
```java ```java
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) { public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
// 获取子标签 // 获取子标签
@ -634,8 +581,6 @@ public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides over
} }
``` ```
使用案例 使用案例
```xml ```xml
@ -659,10 +604,6 @@ public class LookupMain {
} }
``` ```
### parseReplacedMethodSubElements ### parseReplacedMethodSubElements
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseReplacedMethodSubElements` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseReplacedMethodSubElements`
@ -710,12 +651,8 @@ public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides over
} }
``` ```
- 使用案例 - 使用案例
```xml ```xml
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@ -735,8 +672,6 @@ public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides over
</beans> </beans>
``` ```
```java ```java
public class MethodReplacerApple implements MethodReplacer { public class MethodReplacerApple implements MethodReplacer {
@Override @Override
@ -749,20 +684,12 @@ public class MethodReplacerApple implements MethodReplacer {
**replacer 需要使用 MethodReplacer 实现类** **replacer 需要使用 MethodReplacer 实现类**
### parseConstructorArgElements ### parseConstructorArgElements
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseConstructorArgElements` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseConstructorArgElements`
- 解析`constructor-arg`标签 - 解析`constructor-arg`标签
``` ```
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) { public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
// 获取 // 获取
@ -777,10 +704,6 @@ public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
} }
``` ```
```java ```java
public void parseConstructorArgElement(Element ele, BeanDefinition bd) { public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
// 获取 index 属性 // 获取 index 属性
@ -857,8 +780,6 @@ public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
} }
``` ```
### parseConstructorArgElement ### parseConstructorArgElement
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseConstructorArgElement` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseConstructorArgElement`
@ -928,10 +849,6 @@ public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable Strin
} }
``` ```
### parsePropertySubElement ### parsePropertySubElement
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertySubElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)` - `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 ### parsePropertySubElement
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertySubElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition, java.lang.String)` - `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 #### parseIdRefElement
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseIdRefElement`
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseIdRefElement`
```java ```java
@Nullable @Nullable
@ -1058,14 +967,10 @@ public Object parseIdRefElement(Element ele) {
} }
``` ```
#### parseValueElement #### parseValueElement
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseValueElement` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseValueElement`
```JAVA ```JAVA
public Object parseValueElement(Element ele, @Nullable String defaultTypeName) { public Object parseValueElement(Element ele, @Nullable String defaultTypeName) {
// It's a literal value. // It's a literal value.
@ -1093,10 +998,6 @@ public Object parseIdRefElement(Element ele) {
``` ```
##### buildTypedStringValue ##### buildTypedStringValue
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#buildTypedStringValue` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#buildTypedStringValue`
@ -1144,8 +1045,6 @@ public Object parseArrayElement(Element arrayEle, @Nullable BeanDefinition bd) {
} }
``` ```
#### parseListElement #### parseListElement
```java ```java
@ -1176,10 +1075,6 @@ public Set<Object> parseSetElement(Element collectionEle, @Nullable BeanDefiniti
} }
``` ```
##### parseCollectionElements ##### parseCollectionElements
- `parseArrayElement`、`parseListElement`、`parseSetElement` 都围绕者下面这个方法进行数据合并 - `parseArrayElement`、`parseListElement`、`parseSetElement` 都围绕者下面这个方法进行数据合并
@ -1198,8 +1093,6 @@ protected void parseCollectionElements(
} }
``` ```
#### parseMapElement #### parseMapElement
```java ```java
@ -1342,20 +1235,8 @@ public Map<Object, Object> parseMapElement(Element mapEle, @Nullable BeanDefinit
} }
``` ```
#### parsePropsElement #### parsePropsElement
### parsePropertyElement ### parsePropertyElement
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertyElement` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertyElement`
@ -1389,12 +1270,6 @@ public void parsePropertyElement(Element ele, BeanDefinition bd) {
} }
``` ```
### parseQualifierElements ### parseQualifierElements
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseQualifierElements` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseQualifierElements`
@ -1413,10 +1288,6 @@ public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
} }
``` ```
### parseQualifierElement ### parseQualifierElement
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseQualifierElement` - `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseQualifierElement`

@ -1,13 +1,11 @@
# Spring BeanDefinitionReaderUtils # Spring BeanDefinitionReaderUtils
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
## createBeanDefinition ## createBeanDefinition
- `org.springframework.beans.factory.support.BeanDefinitionReaderUtils.createBeanDefinition`
- `org.springframework.beans.factory.support.BeanDefinitionReaderUtils.createBeanDefinition`
```java ```java
public static AbstractBeanDefinition createBeanDefinition( public static AbstractBeanDefinition createBeanDefinition(
@ -31,8 +29,6 @@ public static AbstractBeanDefinition createBeanDefinition(
} }
``` ```
## generateBeanName ## generateBeanName
- `org.springframework.beans.factory.support.BeanDefinitionReaderUtils.generateBeanName(org.springframework.beans.factory.config.BeanDefinition, org.springframework.beans.factory.support.BeanDefinitionRegistry, boolean)` - `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 ## uniqueBeanName
```java ```java
@ -96,10 +90,6 @@ public static String uniqueBeanName(String beanName, BeanDefinitionRegistry regi
} }
``` ```
## registerBeanDefinition ## registerBeanDefinition
```java ```java
@ -125,10 +115,6 @@ public static void registerBeanDefinition(
} }
``` ```
## registerWithGeneratedName ## registerWithGeneratedName
```java ```java

@ -1,12 +1,11 @@
# Spring BeanNameGenerator # Spring BeanNameGenerator
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- `org.springframework.beans.factory.support.BeanNameGenerator` - `org.springframework.beans.factory.support.BeanNameGenerator`
- 方法用来生成 beanName - 方法用来生成 beanName
```java ```java
public interface BeanNameGenerator { public interface BeanNameGenerator {
@ -23,20 +22,12 @@ public interface BeanNameGenerator {
} }
``` ```
![](/images/spring/BeanNameGenerator.png) ![](/images/spring/BeanNameGenerator.png)
## DefaultBeanNameGenerator ## DefaultBeanNameGenerator
- `org.springframework.beans.factory.support.DefaultBeanNameGenerator` - `org.springframework.beans.factory.support.DefaultBeanNameGenerator`
- 调用工具类方法进行生成 - 调用工具类方法进行生成
```JAVA ```JAVA
@ -46,11 +37,9 @@ public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry
} }
``` ```
1. ClassName + # + 十六进制字符 1. ClassName + # + 十六进制字符
2. parentName + $child + # + 十六进制字符 2. parentName + \$child + # + 十六进制字符
3. factoryBeanName +$created+# + 十六进制字符 3. factoryBeanName +\$created+# + 十六进制字符
4. beanName + # + 序号 4. beanName + # + 序号
```java ```java
@ -93,10 +82,6 @@ public static String generateBeanName(
} }
``` ```
## AnnotationBeanNameGenerator ## AnnotationBeanNameGenerator
1. 获取注解的 value 作为 beanName 1. 获取注解的 value 作为 beanName
@ -122,10 +107,6 @@ public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry
} }
``` ```
## FullyQualifiedAnnotationBeanNameGenerator ## FullyQualifiedAnnotationBeanNameGenerator
- 全类名 - 全类名

@ -1,19 +1,16 @@
# Spring MethodOverride # Spring MethodOverride
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- `org.springframework.beans.factory.support.MethodOverride` - `org.springframework.beans.factory.support.MethodOverride`
- `org.springframework.beans.factory.support.LookupOverride` - `org.springframework.beans.factory.support.LookupOverride`
- `org.springframework.beans.factory.support.ReplaceOverride` - `org.springframework.beans.factory.support.ReplaceOverride`
- `org.springframework.beans.factory.support.MethodOverrides` - `org.springframework.beans.factory.support.MethodOverrides`
## MethodOverride ## MethodOverride
- MethodOverride 方法重载类
- MethodOverride 方法重载类
在`MethodOverride`定义了下面三个属性 在`MethodOverride`定义了下面三个属性
@ -48,16 +45,10 @@ public abstract class MethodOverride implements BeanMetadataElement {
public abstract boolean matches(Method method); public abstract boolean matches(Method method);
``` ```
类图 类图
![MethodOverride](/images/spring/MethodOverride.png) ![MethodOverride](/images/spring/MethodOverride.png)
- 在 Spring 中有两种可以重写的机制(XML) - 在 Spring 中有两种可以重写的机制(XML)
1. `lookup-method` 标签 1. `lookup-method` 标签
@ -66,22 +57,14 @@ public abstract boolean matches(Method method);
<lookup-method name="" bean=""/> <lookup-method name="" bean=""/>
``` ```
2. `replaced-method` 标签 2. `replaced-method` 标签
```xml ```xml
<replaced-method name="" replacer=""/> <replaced-method name="" replacer=""/>
``` ```
相对应的两个类如类图所示 相对应的两个类如类图所示
## LookupOverride ## LookupOverride
- `org.springframework.beans.factory.support.LookupOverride` - `org.springframework.beans.factory.support.LookupOverride`
@ -100,17 +83,15 @@ private final String beanName;
private Method method; private Method method;
``` ```
### matches ### matches
比较方法 比较方法
1. method 是否直接相等 1. method 是否直接相等
1. method 名称是否相同 1. method 名称是否相同
2. 是否需要重载 1. 是否需要重载
3. 是不是 ABSTRACT 方法 1. 是不是 ABSTRACT 方法
4. 参数列表长度是否等于0 1. 参数列表长度是否等于 0
```java ```java
@Override @Override
@ -131,10 +112,6 @@ private Method method;
``` ```
## ReplaceOverride ## ReplaceOverride
- `org.springframework.beans.factory.support.ReplaceOverride` - `org.springframework.beans.factory.support.ReplaceOverride`
@ -152,8 +129,6 @@ private final String methodReplacerBeanName;
private final List<String> typeIdentifiers = new LinkedList<>(); private final List<String> typeIdentifiers = new LinkedList<>();
``` ```
- 一个例子 - 一个例子
```XML ```XML
@ -175,18 +150,12 @@ private final List<String> typeIdentifiers = new LinkedList<>();
</beans> </beans>
``` ```
methodReplacerBeanName 对应`org.springframework.beans.factory.support.MethodReplacer` 的实现类 methodReplacerBeanName 对应`org.springframework.beans.factory.support.MethodReplacer` 的实现类
typeIdentifiers 对应标签 arg-type 的属性值 typeIdentifiers 对应标签 arg-type 的属性值
构造方法 构造方法
```java ```java
public ReplaceOverride(String methodName, String methodReplacerBeanName) { public ReplaceOverride(String methodName, String methodReplacerBeanName) {
super(methodName); super(methodName);
@ -195,18 +164,10 @@ public ReplaceOverride(String methodName, String methodReplacerBeanName) {
} }
``` ```
methodName 通过父类进行设置 methodName 通过父类进行设置
### matches ### matches
```java ```java
@Override @Override
public boolean matches(Method method) { public boolean matches(Method method) {
@ -237,12 +198,6 @@ public boolean matches(Method method) {
} }
``` ```
## MethodOverrides ## MethodOverrides
- `org.springframework.beans.factory.support.MethodOverrides` - `org.springframework.beans.factory.support.MethodOverrides`
@ -255,14 +210,8 @@ public boolean matches(Method method) {
private final Set<MethodOverride> overrides = new CopyOnWriteArraySet<>(); private final Set<MethodOverride> overrides = new CopyOnWriteArraySet<>();
``` ```
几个方法 几个方法
1. 添加 MethodOverride 1. 添加 MethodOverride
```java ```java

@ -1,4 +1,5 @@
# Spring MultiValueMap # Spring MultiValueMap
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
@ -55,16 +56,10 @@ public interface MultiValueMap<K, V> extends Map<K, List<V>> {
- 但从接口定义上可以明确 value 是一个 list 结构 - 但从接口定义上可以明确 value 是一个 list 结构
类图 类图
![](/images/spring/MultiValueMap.png) ![](/images/spring/MultiValueMap.png)
## LinkedMultiValueMap ## LinkedMultiValueMap
```java ```java

@ -3,35 +3,24 @@
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 相关类 - 相关类
- `org.springframework.beans.PropertyValues` - `org.springframework.beans.PropertyValues`
- `org.springframework.beans.PropertyValue` - `org.springframework.beans.PropertyValue`
- `org.springframework.beans.MutablePropertyValues` - `org.springframework.beans.MutablePropertyValues`
- 类图如下 - 类图如下
![images](/images/spring/PropertyValues.png) ![images](/images/spring/PropertyValues.png)
- 在 Spring IoC 中,**非 Web 工程**,使用 xml 或者注解进行配置主要使用到的是 `PropertyValues` `PropertyValue` `MutablePropertyValues` 三个 - 在 Spring IoC 中,**非 Web 工程**,使用 xml 或者注解进行配置主要使用到的是 `PropertyValues` `PropertyValue` `MutablePropertyValues` 三个
其中 `PropertyValues` 是继承迭代器,具体实现在`MutablePropertyValues` 他们处理的对象是`PropertyValues` 其中 `PropertyValues` 是继承迭代器,具体实现在`MutablePropertyValues` 他们处理的对象是`PropertyValues`
关系就是这样. 关系就是这样.
- 开始类的解析了 - 开始类的解析了
## PropertyValue ## PropertyValue
- `org.springframework.beans.PropertyValue` - `org.springframework.beans.PropertyValue`
@ -49,10 +38,6 @@
属性值一一对应填入. 属性值一一对应填入.
## MutablePropertyValues ## MutablePropertyValues
- `org.springframework.beans.MutablePropertyValues` - `org.springframework.beans.MutablePropertyValues`
@ -62,8 +47,6 @@
2. `processedProperties`: 已经处理的属性名称 2. `processedProperties`: 已经处理的属性名称
3. `converted`: 是否转换 3. `converted`: 是否转换
```java ```java
public class MutablePropertyValues implements PropertyValues, Serializable { public class MutablePropertyValues implements PropertyValues, Serializable {
/** /**
@ -84,8 +67,6 @@ public class MutablePropertyValues implements PropertyValues, Serializable {
} }
``` ```
### 构造器 ### 构造器
- `MutablePropertyValues` 的一个构造器. 其他构造器的方式原理实现差不多. 核心是将构造参数转换成`PropertyValue`对象在放入`propertyValueList`中 - `MutablePropertyValues` 的一个构造器. 其他构造器的方式原理实现差不多. 核心是将构造参数转换成`PropertyValue`对象在放入`propertyValueList`中
@ -109,16 +90,8 @@ public MutablePropertyValues(@Nullable PropertyValues original) {
} }
``` ```
### PropertyValue 的构造方法 ### PropertyValue 的构造方法
```JAVA ```JAVA
public PropertyValue(PropertyValue original) { public PropertyValue(PropertyValue original) {
Assert.notNull(original, "Original must not be null"); Assert.notNull(original, "Original must not be null");
@ -135,17 +108,9 @@ public MutablePropertyValues(@Nullable PropertyValues original) {
``` ```
- 除了最后一行是一个复杂调用. 前面几行代码都是属性赋值操作. - 除了最后一行是一个复杂调用. 前面几行代码都是属性赋值操作.
- 最后一行代码会调用`AttributeAccessor`接口上的方法. - 最后一行代码会调用`AttributeAccessor`接口上的方法.
## AttributeAccessor ## AttributeAccessor
- `org.springframework.core.AttributeAccessor` - `org.springframework.core.AttributeAccessor`
@ -194,16 +159,8 @@ public interface AttributeAccessor {
} }
``` ```
- 回到`org.springframework.core.AttributeAccessorSupport#copyAttributesFrom`方法 - 回到`org.springframework.core.AttributeAccessorSupport#copyAttributesFrom`方法
```java ```java
protected void copyAttributesFrom(AttributeAccessor source) { protected void copyAttributesFrom(AttributeAccessor source) {
Assert.notNull(source, "Source must not be null"); Assert.notNull(source, "Source must not be null");
@ -218,10 +175,6 @@ protected void copyAttributesFrom(AttributeAccessor source) {
} }
``` ```
### setAttribute ### setAttribute
- 一个 map 操作 - 一个 map 操作
@ -239,8 +192,6 @@ public void setAttribute(String name, @Nullable Object value) {
} }
``` ```
## addPropertyValue ## addPropertyValue
- `org.springframework.beans.MutablePropertyValues#addPropertyValue(org.springframework.beans.PropertyValue)` - `org.springframework.beans.MutablePropertyValues#addPropertyValue(org.springframework.beans.PropertyValue)`
@ -268,16 +219,10 @@ public void setAttribute(String name, @Nullable Object value) {
``` ```
## mergeIfRequired ## mergeIfRequired
- `org.springframework.beans.MutablePropertyValues#mergeIfRequired` - `org.springframework.beans.MutablePropertyValues#mergeIfRequired`
- 这段代码会取舍新老数据. - 这段代码会取舍新老数据.
1. 如果是`Mergeable`类型会做合并操作 1. 如果是`Mergeable`类型会做合并操作
2. 直接返回新数据 2. 直接返回新数据
@ -299,8 +244,6 @@ public void setAttribute(String name, @Nullable Object value) {
``` ```
- 配合测试代码,跟容易看懂. - 配合测试代码,跟容易看懂.
```java ```java
@ -320,28 +263,12 @@ public void setAttribute(String name, @Nullable Object value) {
} }
``` ```
## Mergeable ## Mergeable
新的接口`Mergeable` 新的接口`Mergeable`
- `org.springframework.beans.Mergeable` - `org.springframework.beans.Mergeable`
```java ```java
public interface Mergeable { public interface Mergeable {
@ -358,16 +285,10 @@ public interface Mergeable {
} }
``` ```
![](/images/spring/Mergeable.png) ![](/images/spring/Mergeable.png)
- 看一下 List 怎么实现`merge` - 看一下 List 怎么实现`merge`
```java ```java
@Override @Override
@SuppressWarnings("unchecked") @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` - 类全路径: `org.springframework.util.PropertyPlaceholderHelper`
## parseStringValue ## parseStringValue
- `org.springframework.util.PropertyPlaceholderHelper#parseStringValue` 这个方法是主要方法 - `org.springframework.util.PropertyPlaceholderHelper#parseStringValue` 这个方法是主要方法
```java ```java
protected String parseStringValue( protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) { String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {
@ -87,8 +77,6 @@ protected String parseStringValue(
} }
``` ```
在这里还需要关注一个接口 在这里还需要关注一个接口
- 占位符解析. - 占位符解析.
@ -107,12 +95,8 @@ public interface PlaceholderResolver {
} }
``` ```
占位符解析请查看: [PlaceholderResolver](PlaceholderResolver) 占位符解析请查看: [PlaceholderResolver](PlaceholderResolver)
## findPlaceholderEndIndex ## findPlaceholderEndIndex
- 寻找结尾占位符索引 - 寻找结尾占位符索引
@ -145,10 +129,3 @@ private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
return -1; return -1;
} }
``` ```

@ -3,9 +3,6 @@
- Author: [HuiFer](https://github.com/huifer) - Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
## MutablePropertySources ## MutablePropertySources
- 全路径: `org.springframework.core.env.MutablePropertySources` - 全路径: `org.springframework.core.env.MutablePropertySources`
@ -14,8 +11,6 @@
- 类注解如下 - 类注解如下
```java ```java
public class MutablePropertySources implements PropertySources { public class MutablePropertySources implements PropertySources {
@ -238,10 +233,6 @@ public class MutablePropertySources implements PropertySources {
} }
``` ```
## PropertySources ## PropertySources
- 类路径: `org.springframework.core.env.PropertySources` - 类路径: `org.springframework.core.env.PropertySources`
@ -278,22 +269,13 @@ public interface PropertySources extends Iterable<PropertySource<?>> {
} }
``` ```
## PropertySource ## PropertySource
- 类路径: `org.springframework.core.env.PropertySource` - 类路径: `org.springframework.core.env.PropertySource`
- 存有两个子类 - 存有两个子类
1. StubPropertySource 1. StubPropertySource
2. ComparisonPropertySource 2. ComparisonPropertySource 3. 调用`getSource`、`containsProperty`、`getProperty` 都会直接异常
3. 调用`getSource`、`containsProperty`、`getProperty` 都会直接异常
```java ```java
public abstract class PropertySource<T> { public abstract class PropertySource<T> {
@ -500,10 +482,6 @@ public abstract class PropertySource<T> {
} }
``` ```
类图 类图
![PropertySource.png](/images/spring/PropertySource.png) ![PropertySource.png](/images/spring/PropertySource.png)

@ -1,7 +1,6 @@
# Spring SystemPropertyUtils # Spring SystemPropertyUtils
- spring 中获取系统属性的工具类
- spring 中获取系统属性的工具类
- 内部属性 - 内部属性
@ -39,18 +38,12 @@ private static final PropertyPlaceholderHelper nonStrictHelper =
new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, true); new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, true);
``` ```
## resolvePlaceholders ## resolvePlaceholders
- 解析属性 - 解析属性
![SystemPropertyUtils-resolvePlaceholders.png](/images/spring/SystemPropertyUtils-resolvePlaceholders.png) ![SystemPropertyUtils-resolvePlaceholders.png](/images/spring/SystemPropertyUtils-resolvePlaceholders.png)
时序图因为有递归所以看着有点长, 其核心方法最后会指向 PlaceholderResolver 时序图因为有递归所以看着有点长, 其核心方法最后会指向 PlaceholderResolver
通过 PlaceholderResolver 获取属性值 通过 PlaceholderResolver 获取属性值

@ -4,9 +4,9 @@
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read) - 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
- 源码路径: `org.springframework.jms.annotation.EnableJms` - 源码路径: `org.springframework.jms.annotation.EnableJms`
- `org.springframework.web.servlet.HandlerMapping` - `org.springframework.web.servlet.HandlerMapping`
- HandlerMapping 处理映射关系, 通过请求转换成对象`HandlerExecutionChain` - HandlerMapping 处理映射关系, 通过请求转换成对象`HandlerExecutionChain`
```java ```java
public interface HandlerMapping { public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
@ -14,14 +14,8 @@ public interface HandlerMapping {
} }
``` ```
![image](/images/springMVC/HandlerMapping.png) ![image](/images/springMVC/HandlerMapping.png)
```java ```java
@Override @Override
@Nullable @Nullable
@ -62,8 +56,6 @@ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws
} }
``` ```
- `getHandlerInternal`方法是一个抽象方法 - `getHandlerInternal`方法是一个抽象方法
```JAVA ```JAVA
@ -75,14 +67,8 @@ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws
![image-20200915135933146](images/image-20200915135933146.png) ![image-20200915135933146](images/image-20200915135933146.png)
- 先看`org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal`方法是怎么一回事. - 先看`org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal`方法是怎么一回事.
```java ```java
@Override @Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
@ -105,12 +91,6 @@ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws
``` ```
## UrlPathHelper ## UrlPathHelper
- 全路径:`org.springframework.web.util.UrlPathHelper` - 全路径:`org.springframework.web.util.UrlPathHelper`
@ -136,14 +116,8 @@ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws
private String defaultEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING; private String defaultEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
``` ```
### getPathWithinApplication ### getPathWithinApplication
```java ```java
public String getPathWithinApplication(HttpServletRequest request) { public String getPathWithinApplication(HttpServletRequest request) {
// 获取 context path // 获取 context path
@ -172,10 +146,6 @@ public String getPathWithinApplication(HttpServletRequest request) {
3. decode 3. decode
3. 获取剩余路径 3. 获取剩余路径
### getContextPath ### getContextPath
- 获取 context-path 地址 - 获取 context-path 地址
@ -196,10 +166,6 @@ public String getContextPath(HttpServletRequest request) {
} }
``` ```
### decodeRequestString ### decodeRequestString
- 判断是否需要编码, 需要编码就做编码操作,不需要就直接返回 - 判断是否需要编码, 需要编码就做编码操作,不需要就直接返回
@ -215,12 +181,6 @@ public String decodeRequestString(HttpServletRequest request, String source) {
} }
``` ```
### decodeInternal ### decodeInternal
- 编码方法 - 编码方法
@ -245,16 +205,10 @@ private String decodeInternal(HttpServletRequest request, String source) {
} }
``` ```
### determineEncoding ### determineEncoding
- 确认编码 - 确认编码
```java ```java
protected String determineEncoding(HttpServletRequest request) { protected String determineEncoding(HttpServletRequest request) {
// 从 request 中获取编码方式 // 从 request 中获取编码方式
@ -267,10 +221,6 @@ protected String determineEncoding(HttpServletRequest request) {
} }
``` ```
### getRequestUri ### getRequestUri
- 获取 uri 地址 - 获取 uri 地址
@ -289,10 +239,6 @@ protected String determineEncoding(HttpServletRequest request) {
``` ```
### decodeAndCleanUriString ### decodeAndCleanUriString
- 编码和清理数据 - 编码和清理数据
@ -309,12 +255,6 @@ private String decodeAndCleanUriString(HttpServletRequest request, String uri) {
} }
``` ```
### shouldRemoveTrailingServletPathSlash ### shouldRemoveTrailingServletPathSlash
- 是否删除 servlet path 后的斜杠 - 是否删除 servlet path 后的斜杠
@ -359,10 +299,6 @@ private boolean shouldRemoveTrailingServletPathSlash(HttpServletRequest request)
} }
``` ```
### decodeMatrixVariables ### decodeMatrixVariables
- 编码修改方法 - 编码修改方法
@ -391,8 +327,6 @@ public MultiValueMap<String, String> decodeMatrixVariables(
- 与这个方法对应的还有`decodePathVariables` - 与这个方法对应的还有`decodePathVariables`
### decodePathVariables ### decodePathVariables
```java ```java
@ -410,32 +344,20 @@ public Map<String, String> decodePathVariables(HttpServletRequest request, Map<S
} }
``` ```
- 回到`org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal` - 回到`org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal`
```JAVA ```JAVA
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
``` ```
- 设置属性上锁开锁就不具体展开了. - 设置属性上锁开锁就不具体展开了.
## lookupHandlerMethod ## lookupHandlerMethod
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod` 方法 - `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod` 方法
- 第一部分 - 第一部分
```java ```java
@Nullable @Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
@ -457,8 +379,6 @@ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletReques
} }
``` ```
- 创建一个匹配 list,将匹配结果放入 - 创建一个匹配 list,将匹配结果放入
``` ```
@ -511,8 +431,6 @@ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletReques
} }
``` ```
- `getMatchingMapping` 方法是一个抽象方法 - `getMatchingMapping` 方法是一个抽象方法
```java ```java
@ -528,16 +446,8 @@ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletReques
} }
``` ```
- 第二部分 - 第二部分
```java ```java
if (!matches.isEmpty()) { if (!matches.isEmpty()) {
// 比较对象 // 比较对象
@ -573,10 +483,6 @@ else {
} }
``` ```
- 一行行开始分析 - 一行行开始分析
```java ```java
@ -603,8 +509,6 @@ protected abstract Comparator<T> getMappingComparator(HttpServletRequest request
- 执行完成比较方法后创建对象`MatchComparator` - 执行完成比较方法后创建对象`MatchComparator`
- 对象创建后进行排序,排序后取出第一个元素作为后续操作的基准对象 - 对象创建后进行排序,排序后取出第一个元素作为后续操作的基准对象
```java ```java
// 排序 // 排序
matches.sort(comparator); matches.sort(comparator);
@ -612,10 +516,6 @@ matches.sort(comparator);
Match bestMatch = matches.get(0); Match bestMatch = matches.get(0);
``` ```
```java ```java
if (matches.size() > 1) { if (matches.size() > 1) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
@ -643,12 +543,8 @@ if (matches.size() > 1) {
- 取出第一个元素和第二个元素进行比较. 如果两个 match 相同, 出现异常 - 取出第一个元素和第二个元素进行比较. 如果两个 match 相同, 出现异常
最后两个方法 最后两个方法
```java ```java
// 设置属性 // 设置属性
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod); request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
@ -662,8 +558,6 @@ else {
} }
``` ```
- `handleMatch` - `handleMatch`
```java ```java
@ -678,8 +572,6 @@ else {
- `org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleMatch` - `org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleMatch`
```java ```java
@Override @Override
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) { protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
@ -723,10 +615,6 @@ protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServl
} }
``` ```
- `handleNoMatch` 也是同类型操作 - `handleNoMatch` 也是同类型操作
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#handleNoMatch` - `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#handleNoMatch`
- `org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleNoMatch` - `org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleNoMatch`
@ -783,10 +671,3 @@ protected HandlerMethod handleNoMatch(
return null; return null;
} }
``` ```

@ -5,9 +5,7 @@
- 源码路径: `org.springframework.jms.annotation.EnableJms` - 源码路径: `org.springframework.jms.annotation.EnableJms`
- 类全路径 - 类全路径
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry` - `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry`
- 基本属性 - 基本属性
```java ```java
@ -50,10 +48,6 @@
} }
``` ```
- 写一个简单的 controller 来进行解析 - 写一个简单的 controller 来进行解析
```java ```java
@ -67,8 +61,6 @@ public class DemoController {
} }
``` ```
- 前置链路追踪 - 前置链路追踪
- `org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#registerHandlerMethod` - `org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#registerHandlerMethod`
@ -96,10 +88,6 @@ public class DemoController {
![image-20200918130340555](/images/springMVC/clazz/image-20200918130340555.png) ![image-20200918130340555](/images/springMVC/clazz/image-20200918130340555.png)
## createHandlerMethod ## createHandlerMethod
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#createHandlerMethod` - `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#createHandlerMethod`
@ -116,10 +104,6 @@ protected HandlerMethod createHandlerMethod(Object handler, Method method) {
} }
``` ```
- HandlerMethod 构造函数 - HandlerMethod 构造函数
```java ```java
@ -128,10 +112,6 @@ protected HandlerMethod createHandlerMethod(Object handler, Method method) {
public HandlerMethod(Object bean, Method method) {} public HandlerMethod(Object bean, Method method) {}
``` ```
## HandlerMethod ## HandlerMethod
- 成员变量 - 成员变量
@ -172,10 +152,6 @@ public class HandlerMethod {
} }
``` ```
## validateMethodMapping ## validateMethodMapping
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#validateMethodMapping` - `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#validateMethodMapping`
@ -197,8 +173,6 @@ private void validateMethodMapping(HandlerMethod handlerMethod, T mapping) {
} }
``` ```
## getDirectUrls ## getDirectUrls
- 找到 mapping 匹配的 url - 找到 mapping 匹配的 url
@ -219,8 +193,6 @@ private List<String> getDirectUrls(T mapping) {
} }
``` ```
## handlerMethod 和 name 绑定 ## handlerMethod 和 name 绑定
```java ```java
@ -236,8 +208,6 @@ if (getNamingStrategy() != null) {
- `org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMethodMappingNamingStrategy#getName` - `org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMethodMappingNamingStrategy#getName`
```java ```java
@Override @Override
public String getName(HandlerMethod handlerMethod, RequestMappingInfo mapping) { public String getName(HandlerMethod handlerMethod, RequestMappingInfo mapping) {
@ -259,16 +229,10 @@ public String getName(HandlerMethod handlerMethod, RequestMappingInfo mapping) {
} }
``` ```
## initCorsConfiguration ## initCorsConfiguration
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initCorsConfiguration` - `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initCorsConfiguration`
```java ```java
@Override @Override
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) { protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) {
@ -301,12 +265,6 @@ protected CorsConfiguration initCorsConfiguration(Object handler, Method method,
} }
``` ```
## unregister ## unregister
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#unregister` - `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#unregister`

@ -326,7 +326,6 @@ public @interface EnableConfigurationProperties {
```yml ```yml
server: server:
port: 9999 port: 9999
``` ```
- 具体方法: `org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#bind` - 具体方法: `org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#bind`

@ -1,21 +1,47 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<title></title> <title></title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <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
<meta name="description" content="读尽天下源码,心中自然无码,《源码猎人》项目维护者:云之君"> name="keywords"
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> content="doc,docs,doocs,documentation,github,gitee,source-code-hunter,AmyliaY"
<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" /> <meta
<link rel="icon" type="image/png" sizes="32x32" href="images/favicon-32x32.png"> name="description"
<link rel="icon" type="image/png" sizes="16x16" href="images/favicon-16x16.png"> 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> </head>
<body> <body>
<nav> <nav>
<ul> <ul>
<li> <li>
<ul> <ul>
<li><a href="#/?id=spring-系列">Spring</a></li> <li><a href="#/?id=spring-系列">Spring</a></li>
<li><a href="#/?id=mybatis">Mybatis</a></li> <li><a href="#/?id=mybatis">Mybatis</a></li>
@ -25,45 +51,47 @@
<li><a href="#/?id=学习心得"></a></li> <li><a href="#/?id=学习心得"></a></li>
</ul> </ul>
</li> </li>
<li> <li>
<ul> <ul>
<li><a href="#/README"></a></li> <li><a href="#/README"></a></li>
<li><a href="https://github.com/doocs" target="_blank">Doocs</a></li> <li>
<li><a href="https://github.com/AmyliaY" target="_blank">Author</a></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> </ul>
</li> </li>
</ul> </ul>
</nav> </nav>
<div id="app"> Doocs </div> <div id="app"> Doocs </div>
<script> <script>
window.$docsify = { window.$docsify = {
name: 'source-code-hunter', name: "source-code-hunter",
maxLevel: 3, maxLevel: 3,
auto2top: true, auto2top: true,
search: [ search: ["/"],
'/'
],
darkMode: { darkMode: {
light: { light: {
toggleBtnBg: '#42b983' toggleBtnBg: "#42b983",
} },
}, },
plugins: [ plugins: [
function (hook) { function (hook) {
var footer = [ var footer = [
'<hr/>', "<hr/>",
'<footer>', "<footer>",
'<span>Copyright © 2018-2020 <a href="https://github.com/doocs" target="_blank">Doocs</a>. All rights reserved.', '<span>Copyright © 2018-2020 <a href="https://github.com/doocs" target="_blank">Doocs</a>. All rights reserved.',
'</footer>' "</footer>",
].join('') ].join("");
hook.afterEach(function (html) { hook.afterEach(function (html) {
return html + footer return html + footer;
}) });
} },
] ],
} };
</script> </script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></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-c.min.js"></script>

Loading…
Cancel
Save