diff --git a/.babelrc b/.babelrc
new file mode 100644
index 00000000..55754d07
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,3 @@
+{
+ "compact": false
+}
diff --git a/.editorconfig b/.editorconfig
index ee762040..d72a75ea 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -19,7 +19,7 @@ insert_final_newline = true
[*.{bat, cmd}]
end_of_line = crlf
-[*.{java, gradle, groovy, kt, sh, xml}]
+[*.{java, gradle, groovy, kt, sh}]
indent_size = 4
[*.md]
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 36b705cb..04010943 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -15,7 +15,7 @@ jobs:
strategy:
matrix:
- node-version: [14.x]
+ node-version: [16.x]
steps:
# 使用的动作。格式:userName/repoName。作用:检出仓库,获取源码。 官方actions库:https://github.com/actions
diff --git a/README.md b/README.md
index 11f3a7db..7d3dbdd3 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
children = client.getChildren().forPath("/zkid");
+ if (CollectionUtil.isNotEmpty(children)) {
+ for (String child : children) {
+ client.delete().forPath("/zkid/" + child);
+ }
+ }
+ client.delete().forPath("/zkid");
+
+ // 关闭客户端
+ client.close();
+ }
+
+}
diff --git a/codes/java-distributed/java-distributed-id/src/main/java/io/github/dunwu/distributed/id/ZookeeperDistributedId2.java b/codes/java-distributed/java-distributed-id/src/main/java/io/github/dunwu/distributed/id/ZookeeperDistributedId2.java
new file mode 100644
index 00000000..69d5d543
--- /dev/null
+++ b/codes/java-distributed/java-distributed-id/src/main/java/io/github/dunwu/distributed/id/ZookeeperDistributedId2.java
@@ -0,0 +1,46 @@
+package io.github.dunwu.distributed.id;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.curator.RetryPolicy;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.recipes.atomic.AtomicValue;
+import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+
+/**
+ * ZK 分布式 ID
+ *
+ * 基于原子计数器生成 ID
+ *
+ * @author Zhang Peng
+ * @date 2024-12-20
+ */
+@Slf4j
+public class ZookeeperDistributedId2 {
+
+ public static void main(String[] args) throws Exception {
+
+ // 获取客户端
+ RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
+ CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", retryPolicy);
+ DistributedAtomicLong atomicLong = new DistributedAtomicLong(client, "/zkid", retryPolicy);
+
+ // 开启会话
+ client.start();
+
+ // 基于原子计数器生成 ID
+ AtomicValue id1 = atomicLong.increment();
+ log.info("id: {}", id1.postValue());
+
+ AtomicValue id2 = atomicLong.increment();
+ log.info("id: {}", id2.postValue());
+
+ // 清理节点
+ client.delete().forPath("/zkid");
+
+ // 关闭客户端
+ client.close();
+ }
+
+}
diff --git a/codes/java-distributed/java-distributed-id/src/main/resources/scripts/fixed_window_rate_limit.lua b/codes/java-distributed/java-distributed-id/src/main/resources/scripts/fixed_window_rate_limit.lua
new file mode 100644
index 00000000..e0c9ad00
--- /dev/null
+++ b/codes/java-distributed/java-distributed-id/src/main/resources/scripts/fixed_window_rate_limit.lua
@@ -0,0 +1,21 @@
+-- 缓存 Key
+local key = KEYS[1]
+-- 访问请求数
+local permits = tonumber(ARGV[1])
+-- 过期时间
+local seconds = tonumber(ARGV[2])
+-- 限流阈值
+local limit = tonumber(ARGV[3])
+
+-- 获取统计值
+local count = tonumber(redis.call('GET', key) or "0")
+
+if count + permits > limit then
+ -- 请求拒绝
+ return -1
+else
+ -- 请求通过
+ redis.call('INCRBY', key, permits)
+ redis.call('EXPIRE', key, seconds)
+ return count + permits
+end
\ No newline at end of file
diff --git a/codes/java-distributed/java-distributed-id/src/main/resources/scripts/token_bucket_rate_limit.lua b/codes/java-distributed/java-distributed-id/src/main/resources/scripts/token_bucket_rate_limit.lua
new file mode 100644
index 00000000..541d70c9
--- /dev/null
+++ b/codes/java-distributed/java-distributed-id/src/main/resources/scripts/token_bucket_rate_limit.lua
@@ -0,0 +1,39 @@
+local tokenKey = KEYS[1]
+local timeKey = KEYS[2]
+
+-- 申请令牌数
+local permits = tonumber(ARGV[1])
+-- QPS
+local qps = tonumber(ARGV[2])
+-- 桶的容量
+local capacity = tonumber(ARGV[3])
+-- 当前时间(单位:毫秒)
+local nowMillis = tonumber(ARGV[4])
+-- 填满令牌桶所需要的时间
+local fillTime = capacity / qps
+local ttl = math.min(capacity, math.floor(fillTime * 2))
+
+local currentTokenNum = tonumber(redis.call("GET", tokenKey))
+if currentTokenNum == nil then
+ currentTokenNum = capacity
+end
+
+local endTimeMillis = tonumber(redis.call("GET", timeKey))
+if endTimeMillis == nil then
+ endTimeMillis = 0
+end
+
+local gap = nowMillis - endTimeMillis
+local newTokenNum = math.max(0, gap * qps / 1000)
+local currentTokenNum = math.min(capacity, currentTokenNum + newTokenNum)
+
+if currentTokenNum < permits then
+ -- 请求拒绝
+ return -1
+else
+ -- 请求通过
+ local finalTokenNum = currentTokenNum - permits
+ redis.call("SETEX", tokenKey, ttl, finalTokenNum)
+ redis.call("SETEX", timeKey, ttl, nowMillis)
+ return finalTokenNum
+end
diff --git a/codes/java-distributed/java-load-balance/pom.xml b/codes/java-distributed/java-load-balance/pom.xml
index 5f14ae1a..b4e73f0f 100644
--- a/codes/java-distributed/java-load-balance/pom.xml
+++ b/codes/java-distributed/java-load-balance/pom.xml
@@ -3,11 +3,10 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- io.github.dunwu.javatech
+ io.github.dunwu.distributed
java-load-balance
1.0.0
jar
- ${project.artifactId}
UTF-8
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/BaseLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/BaseLoadBalance.java
similarity index 96%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/BaseLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/BaseLoadBalance.java
index e4f03ab2..ebb317a8 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/BaseLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/BaseLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import cn.hutool.core.collection.CollectionUtil;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/ConsistentHashLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/ConsistentHashLoadBalance.java
similarity index 99%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/ConsistentHashLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/ConsistentHashLoadBalance.java
index 42394a12..c67558a2 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/ConsistentHashLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/ConsistentHashLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/IpHashLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/IpHashLoadBalance.java
similarity index 94%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/IpHashLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/IpHashLoadBalance.java
index 00be0c93..3d71cbb7 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/IpHashLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/IpHashLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.StrUtil;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LeastActiveLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LeastActiveLoadBalance.java
similarity index 98%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LeastActiveLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LeastActiveLoadBalance.java
index 25dc6f13..23a7f03c 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LeastActiveLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LeastActiveLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
import java.util.Random;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalance.java
similarity index 86%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalance.java
index 046734af..f2d0c561 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalanceDemo.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalanceDemo.java
similarity index 97%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalanceDemo.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalanceDemo.java
index 1077f48e..57dc61f1 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/LoadBalanceDemo.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/LoadBalanceDemo.java
@@ -1,6 +1,10 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeMap;
/**
* 负载均衡算法测试例
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/Node.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/Node.java
similarity index 97%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/Node.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/Node.java
index ad0c8ed4..2fc9c712 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/Node.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/Node.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.Objects;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RandomLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RandomLoadBalance.java
similarity index 94%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RandomLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RandomLoadBalance.java
index 8f4b7d8d..5b775dd2 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RandomLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RandomLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
import java.util.Random;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RoundRobinLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RoundRobinLoadBalance.java
similarity index 94%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RoundRobinLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RoundRobinLoadBalance.java
index d14b251d..c0858152 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/RoundRobinLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/RoundRobinLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/StatisticsUtil.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/StatisticsUtil.java
similarity index 95%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/StatisticsUtil.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/StatisticsUtil.java
index 50eaa59a..cbb66d13 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/StatisticsUtil.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/StatisticsUtil.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
public class StatisticsUtil {
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRandomLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRandomLoadBalance.java
similarity index 96%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRandomLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRandomLoadBalance.java
index a3f1c853..c7135667 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRandomLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRandomLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
import java.util.Random;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRoundRobinLoadBalance.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRoundRobinLoadBalance.java
similarity index 99%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRoundRobinLoadBalance.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRoundRobinLoadBalance.java
index 3180958d..3f71a573 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/WeightRoundRobinLoadBalance.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/WeightRoundRobinLoadBalance.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/package-info.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/package-info.java
similarity index 76%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/package-info.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/package-info.java
index 8633bb5a..4d8b7a26 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/package-info.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/package-info.java
@@ -4,4 +4,4 @@
* @author Zhang Peng
* @since 2020-01-22
*/
-package io.github.dunwu.javatech;
+package io.github.dunwu.distributed;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/CRCHashStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/CRCHashStrategy.java
similarity index 98%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/CRCHashStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/CRCHashStrategy.java
index 8622bb51..5c732a5b 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/CRCHashStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/CRCHashStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
import java.nio.charset.StandardCharsets;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/FnvHashStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/FnvHashStrategy.java
similarity index 92%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/FnvHashStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/FnvHashStrategy.java
index 807f3c33..fc7cea13 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/FnvHashStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/FnvHashStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
public class FnvHashStrategy implements HashStrategy {
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/HashStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/HashStrategy.java
similarity index 59%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/HashStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/HashStrategy.java
index 2ad6deef..f574c86e 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/HashStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/HashStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
public interface HashStrategy {
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/JdkHashCodeStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/JdkHashCodeStrategy.java
similarity index 77%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/JdkHashCodeStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/JdkHashCodeStrategy.java
index f4a8389c..6541e2a4 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/JdkHashCodeStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/JdkHashCodeStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
public class JdkHashCodeStrategy implements HashStrategy {
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/KetamaHashStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/KetamaHashStrategy.java
similarity index 96%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/KetamaHashStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/KetamaHashStrategy.java
index 8e98ef1f..ef479aaf 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/KetamaHashStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/KetamaHashStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
diff --git a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/MurmurHashStrategy.java b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/MurmurHashStrategy.java
similarity index 96%
rename from codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/MurmurHashStrategy.java
rename to codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/MurmurHashStrategy.java
index a100f3d3..82ee1620 100644
--- a/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/javatech/support/MurmurHashStrategy.java
+++ b/codes/java-distributed/java-load-balance/src/main/java/io/github/dunwu/distributed/support/MurmurHashStrategy.java
@@ -1,4 +1,4 @@
-package io.github.dunwu.javatech.support;
+package io.github.dunwu.distributed.support;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
diff --git a/codes/java-distributed/java-rate-limit/pom.xml b/codes/java-distributed/java-rate-limit/pom.xml
new file mode 100644
index 00000000..312d7f21
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/pom.xml
@@ -0,0 +1,41 @@
+
+
+ 4.0.0
+
+ io.github.dunwu.distributed
+ java-rate-limit
+ 1.0.0
+ jar
+
+
+ UTF-8
+ 1.8
+ ${java.version}
+ ${java.version}
+
+
+
+
+ redis.clients
+ jedis
+ 5.1.0
+
+
+ cn.hutool
+ hutool-all
+ 5.8.25
+
+
+ org.projectlombok
+ lombok
+ 1.18.30
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+ true
+
+
+
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/FixedWindowRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/FixedWindowRateLimiter.java
new file mode 100644
index 00000000..0af8d142
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/FixedWindowRateLimiter.java
@@ -0,0 +1,59 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 固定时间窗口限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+public class FixedWindowRateLimiter implements RateLimiter {
+
+ /**
+ * 允许的最大请求数
+ */
+ private final long maxPermits;
+
+ /**
+ * 窗口期时长
+ */
+ private final long periodMillis;
+
+ /**
+ * 窗口期截止时间
+ */
+ private long lastPeriodMillis;
+
+ /**
+ * 请求计数
+ */
+ private AtomicLong count = new AtomicLong(0);
+
+ public FixedWindowRateLimiter(long qps) {
+ this(qps, 1000, TimeUnit.MILLISECONDS);
+ }
+
+ public FixedWindowRateLimiter(long maxPermits, long period, TimeUnit timeUnit) {
+ this.maxPermits = maxPermits;
+ this.periodMillis = timeUnit.toMillis(period);
+ this.lastPeriodMillis = System.currentTimeMillis() + this.periodMillis;
+ }
+
+ @Override
+ public synchronized boolean tryAcquire(int permits) {
+ long now = System.currentTimeMillis();
+ if (lastPeriodMillis <= now) {
+ this.lastPeriodMillis = now + this.periodMillis;
+ count = new AtomicLong(0);
+ }
+ if (count.get() + permits <= maxPermits) {
+ count.addAndGet(permits);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/LeakyBucketRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/LeakyBucketRateLimiter.java
new file mode 100644
index 00000000..0d99a227
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/LeakyBucketRateLimiter.java
@@ -0,0 +1,64 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 漏桶限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+public class LeakyBucketRateLimiter implements RateLimiter {
+
+ /**
+ * QPS
+ */
+ private final int qps;
+
+ /**
+ * 桶的容量
+ */
+ private final long capacity;
+
+ /**
+ * 计算的起始时间
+ */
+ private long beginTimeMillis;
+
+ /**
+ * 桶中当前的水量
+ */
+ private final AtomicLong waterNum = new AtomicLong(0);
+
+ public LeakyBucketRateLimiter(int qps, int capacity) {
+ this.qps = qps;
+ this.capacity = capacity;
+ }
+
+ @Override
+ public synchronized boolean tryAcquire(int permits) {
+
+ // 如果桶中没有水,直接放行
+ if (waterNum.get() == 0) {
+ beginTimeMillis = System.currentTimeMillis();
+ waterNum.addAndGet(permits);
+ return true;
+ }
+
+ // 计算水量
+ long leakedWaterNum = ((System.currentTimeMillis() - beginTimeMillis) / 1000) * qps;
+ long currentWaterNum = waterNum.get() - leakedWaterNum;
+ waterNum.set(Math.max(0, currentWaterNum));
+
+ // 重置时间
+ beginTimeMillis = System.currentTimeMillis();
+
+ if (waterNum.get() + permits < capacity) {
+ waterNum.addAndGet(permits);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiter.java
new file mode 100644
index 00000000..4fbc9646
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiter.java
@@ -0,0 +1,13 @@
+package io.github.dunwu.distributed.ratelimit;
+
+/**
+ * 限流器
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+public interface RateLimiter {
+
+ boolean tryAcquire(int permits);
+
+}
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiterDemo.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiterDemo.java
new file mode 100644
index 00000000..e4a50641
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RateLimiterDemo.java
@@ -0,0 +1,95 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.core.util.RandomUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 限流器示例
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+@Slf4j
+public class RateLimiterDemo {
+
+ public static void main(String[] args) {
+
+ // ============================================================================
+
+ int qps = 20;
+
+ System.out.println("======================= 固定时间窗口限流算法 =======================");
+ FixedWindowRateLimiter fixedWindowRateLimiter = new FixedWindowRateLimiter(qps);
+ testRateLimit(fixedWindowRateLimiter, qps);
+
+ System.out.println("======================= 滑动时间窗口限流算法 =======================");
+ SlidingWindowRateLimiter slidingWindowRateLimiter = new SlidingWindowRateLimiter(qps, 10);
+ testRateLimit(slidingWindowRateLimiter, qps);
+
+ System.out.println("======================= 漏桶限流算法 =======================");
+ LeakyBucketRateLimiter leakyBucketRateLimiter = new LeakyBucketRateLimiter(qps, 100);
+ testRateLimit(leakyBucketRateLimiter, qps);
+
+ System.out.println("======================= 令牌桶限流算法 =======================");
+ TokenBucketRateLimiter tokenBucketRateLimiter = new TokenBucketRateLimiter(qps, 100);
+ testRateLimit(tokenBucketRateLimiter, qps);
+ }
+
+ private static void testRateLimit(RateLimiter rateLimiter, int qps) {
+
+ AtomicInteger okNum = new AtomicInteger(0);
+ AtomicInteger limitNum = new AtomicInteger(0);
+ ExecutorService executorService = ThreadUtil.newFixedExecutor(10, "限流测试", true);
+ long beginTime = System.currentTimeMillis();
+
+ int threadNum = 4;
+ final CountDownLatch latch = new CountDownLatch(threadNum);
+ for (int i = 0; i < threadNum; i++) {
+ executorService.submit(() -> {
+ try {
+ batchRequest(rateLimiter, okNum, limitNum, 1000);
+ } catch (Exception e) {
+ log.error("发生异常!", e);
+ } finally {
+ latch.countDown();
+ }
+ });
+ }
+
+ try {
+ latch.await(10, TimeUnit.SECONDS);
+ long endTime = System.currentTimeMillis();
+ long gap = endTime - beginTime;
+ log.info("限流 QPS: {} -> 实际结果:耗时 {} ms,{} 次请求成功,{} 次请求被限流,实际 QPS: {}",
+ qps, gap, okNum.get(), limitNum.get(), okNum.get() * 1000 / gap);
+ if (okNum.get() == qps) {
+ log.info("限流符合预期");
+ }
+ } catch (Exception e) {
+ log.error("发生异常!", e);
+ } finally {
+ executorService.shutdown();
+ }
+ }
+
+ private static void batchRequest(RateLimiter rateLimiter, AtomicInteger okNum, AtomicInteger limitNum, int num)
+ throws InterruptedException {
+ for (int j = 0; j < num; j++) {
+ if (rateLimiter.tryAcquire(1)) {
+ log.info("请求成功");
+ okNum.getAndIncrement();
+ } else {
+ log.info("请求限流");
+ limitNum.getAndIncrement();
+ }
+ TimeUnit.MILLISECONDS.sleep(RandomUtil.randomInt(0, 10));
+ }
+ }
+
+}
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisFixedWindowRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisFixedWindowRateLimiter.java
new file mode 100644
index 00000000..ec5d77d9
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisFixedWindowRateLimiter.java
@@ -0,0 +1,100 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 基于 Redis + Lua 实现的固定时间窗口限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-23
+ */
+public class RedisFixedWindowRateLimiter implements RateLimiter {
+
+ private static final String REDIS_HOST = "localhost";
+
+ private static final int REDIS_PORT = 6379;
+
+ private static final Jedis JEDIS;
+
+ public static final String SCRIPT;
+
+ static {
+ // Jedis 有多种构造方法,这里选用最简单的一种情况
+ JEDIS = new Jedis(REDIS_HOST, REDIS_PORT);
+
+ // 触发 ping 命令
+ try {
+ JEDIS.ping();
+ System.out.println("jedis 连接成功");
+ } catch (JedisConnectionException e) {
+ e.printStackTrace();
+ }
+
+ SCRIPT = FileUtil.readString(ResourceUtil.getResource("scripts/fixed_window_rate_limit.lua"),
+ StandardCharsets.UTF_8);
+ }
+
+ private final long maxPermits;
+ private final long periodSeconds;
+ private final String key;
+
+ public RedisFixedWindowRateLimiter(long qps, String key) {
+ this(qps * 60, 60, TimeUnit.SECONDS, key);
+ }
+
+ public RedisFixedWindowRateLimiter(long maxPermits, long period, TimeUnit timeUnit, String key) {
+ this.maxPermits = maxPermits;
+ this.periodSeconds = timeUnit.toSeconds(period);
+ this.key = key;
+ }
+
+ @Override
+ public boolean tryAcquire(int permits) {
+ List keys = Collections.singletonList(key);
+ List args = CollectionUtil.newLinkedList(String.valueOf(permits), String.valueOf(periodSeconds),
+ String.valueOf(maxPermits));
+ Object eval = JEDIS.eval(SCRIPT, keys, args);
+ long value = (long) eval;
+ return value != -1;
+ }
+
+ public static void main(String[] args) throws InterruptedException {
+
+ int qps = 20;
+ RateLimiter jedisFixedWindowRateLimiter = new RedisFixedWindowRateLimiter(qps, "rate:limit:20240122210000");
+
+ // 模拟在一分钟内,不断收到请求,限流是否有效
+ int seconds = 60;
+ long okNum = 0L;
+ long total = 0L;
+ long beginTime = System.currentTimeMillis();
+ int num = RandomUtil.randomInt(qps, 100);
+ for (int second = 0; second < seconds; second++) {
+ for (int i = 0; i < num; i++) {
+ total++;
+ if (jedisFixedWindowRateLimiter.tryAcquire(1)) {
+ okNum++;
+ System.out.println("请求成功");
+ } else {
+ System.out.println("请求限流");
+ }
+ }
+ TimeUnit.SECONDS.sleep(1);
+ }
+ long endTime = System.currentTimeMillis();
+ long time = (endTime - beginTime) / 1000;
+ System.out.println(StrUtil.format("请求通过数:{},总请求数:{},实际 QPS:{}", okNum, total, okNum / time));
+ }
+
+}
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisTokenBucketRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisTokenBucketRateLimiter.java
new file mode 100644
index 00000000..9dd219df
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/RedisTokenBucketRateLimiter.java
@@ -0,0 +1,104 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 基于 Redis + Lua 实现的令牌桶限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-23
+ */
+public class RedisTokenBucketRateLimiter implements RateLimiter {
+
+ private static final String REDIS_HOST = "localhost";
+
+ private static final int REDIS_PORT = 6379;
+
+ private static final Jedis JEDIS;
+
+ public static final String SCRIPT;
+
+ static {
+ // Jedis 有多种构造方法,这里选用最简单的一种情况
+ JEDIS = new Jedis(REDIS_HOST, REDIS_PORT);
+
+ // 触发 ping 命令
+ try {
+ JEDIS.ping();
+ System.out.println("jedis 连接成功");
+ } catch (JedisConnectionException e) {
+ e.printStackTrace();
+ }
+
+ SCRIPT = FileUtil.readString(ResourceUtil.getResource("scripts/token_bucket_rate_limit.lua"),
+ StandardCharsets.UTF_8);
+ }
+
+ private final long qps;
+ private final long capacity;
+ private final String tokenKey;
+ private final String timeKey;
+
+ public RedisTokenBucketRateLimiter(long qps, long capacity, String tokenKey, String timeKey) {
+ this.qps = qps;
+ this.capacity = capacity;
+ this.tokenKey = tokenKey;
+ this.timeKey = timeKey;
+ }
+
+ @Override
+ public boolean tryAcquire(int permits) {
+ long now = System.currentTimeMillis();
+ List keys = CollectionUtil.newLinkedList(tokenKey, timeKey);
+ List args = CollectionUtil.newLinkedList(String.valueOf(permits), String.valueOf(qps),
+ String.valueOf(capacity), String.valueOf(now));
+ Object eval = JEDIS.eval(SCRIPT, keys, args);
+ long value = (long) eval;
+ return value != -1;
+ }
+
+ public static void main(String[] args) throws InterruptedException {
+
+ int qps = 20;
+ int bucket = 100;
+ RedisTokenBucketRateLimiter redisTokenBucketRateLimiter =
+ new RedisTokenBucketRateLimiter(qps, bucket, "token:rate:limit", "token:rate:limit:time");
+
+ // 先将令牌桶预热令牌申请完,后续才能真实反映限流 QPS
+ redisTokenBucketRateLimiter.tryAcquire(bucket);
+ TimeUnit.SECONDS.sleep(1);
+
+ // 模拟在一分钟内,不断收到请求,限流是否有效
+ int seconds = 60;
+ long okNum = 0L;
+ long total = 0L;
+ long beginTime = System.currentTimeMillis();
+ for (int second = 0; second < seconds; second++) {
+ int num = RandomUtil.randomInt(qps, 100);
+ for (int i = 0; i < num; i++) {
+ total++;
+ if (redisTokenBucketRateLimiter.tryAcquire(1)) {
+ okNum++;
+ System.out.println("请求成功");
+ } else {
+ System.out.println("请求限流");
+ }
+ }
+ TimeUnit.SECONDS.sleep(1);
+ }
+ long endTime = System.currentTimeMillis();
+ long time = (endTime - beginTime) / 1000;
+ System.out.println(StrUtil.format("请求通过数:{},总请求数:{},实际 QPS:{}", okNum, total, okNum / time));
+ }
+
+}
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/SlidingWindowRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/SlidingWindowRateLimiter.java
new file mode 100644
index 00000000..a93613a2
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/SlidingWindowRateLimiter.java
@@ -0,0 +1,87 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 滑动时间窗口限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+public class SlidingWindowRateLimiter implements RateLimiter {
+
+ /**
+ * 允许的最大请求数
+ */
+ private final long maxPermits;
+
+ /**
+ * 窗口期时长
+ */
+ private final long periodMillis;
+
+ /**
+ * 分片窗口期时长
+ */
+ private final long shardPeriodMillis;
+
+ /**
+ * 窗口期截止时间
+ */
+ private long lastPeriodMillis;
+
+ /**
+ * 分片窗口数
+ */
+ private final int shardNum;
+
+ /**
+ * 请求总计数
+ */
+ private final AtomicLong totalCount = new AtomicLong(0);
+
+ /**
+ * 分片窗口计数列表
+ */
+ private final List countList = new LinkedList<>();
+
+ public SlidingWindowRateLimiter(long qps, int shardNum) {
+ this(qps, 1000, TimeUnit.MILLISECONDS, shardNum);
+ }
+
+ public SlidingWindowRateLimiter(long maxPermits, long period, TimeUnit timeUnit, int shardNum) {
+ this.maxPermits = maxPermits;
+ this.periodMillis = timeUnit.toMillis(period);
+ this.lastPeriodMillis = System.currentTimeMillis();
+ this.shardPeriodMillis = timeUnit.toMillis(period) / shardNum;
+ this.shardNum = shardNum;
+ for (int i = 0; i < shardNum; i++) {
+ countList.add(new AtomicLong(0));
+ }
+ }
+
+ @Override
+ public synchronized boolean tryAcquire(int permits) {
+ long now = System.currentTimeMillis();
+ if (now > lastPeriodMillis) {
+ for (int shardId = 0; shardId < shardNum; shardId++) {
+ long shardCount = countList.get(shardId).get();
+ totalCount.addAndGet(-shardCount);
+ countList.set(shardId, new AtomicLong(0));
+ lastPeriodMillis += shardPeriodMillis;
+ }
+ }
+ int shardId = (int) (now % periodMillis / shardPeriodMillis);
+ if (totalCount.get() + permits <= maxPermits) {
+ countList.get(shardId).addAndGet(permits);
+ totalCount.addAndGet(permits);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/TokenBucketRateLimiter.java b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/TokenBucketRateLimiter.java
new file mode 100644
index 00000000..e03e4c7d
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/java/io/github/dunwu/distributed/ratelimit/TokenBucketRateLimiter.java
@@ -0,0 +1,59 @@
+package io.github.dunwu.distributed.ratelimit;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 令牌桶限流算法
+ *
+ * @author Zhang Peng
+ * @date 2024-01-18
+ */
+public class TokenBucketRateLimiter implements RateLimiter {
+
+ /**
+ * QPS
+ */
+ private final long qps;
+
+ /**
+ * 桶的容量
+ */
+ private final long capacity;
+
+ /**
+ * 上一次令牌发放时间
+ */
+ private long endTimeMillis;
+
+ /**
+ * 桶中当前的令牌数量
+ */
+ private final AtomicLong tokenNum = new AtomicLong(0);
+
+ public TokenBucketRateLimiter(long qps, long capacity) {
+ this.qps = qps;
+ this.capacity = capacity;
+ this.endTimeMillis = System.currentTimeMillis();
+ }
+
+ @Override
+ public synchronized boolean tryAcquire(int permits) {
+
+ long now = System.currentTimeMillis();
+ long gap = now - endTimeMillis;
+
+ // 计算令牌数
+ long newTokenNum = (gap * qps / 1000);
+ long currentTokenNum = tokenNum.get() + newTokenNum;
+ tokenNum.set(Math.min(capacity, currentTokenNum));
+
+ if (tokenNum.get() < permits) {
+ return false;
+ } else {
+ tokenNum.addAndGet(-permits);
+ endTimeMillis = now;
+ return true;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/codes/java-distributed/java-rate-limit/src/main/resources/scripts/fixed_window_rate_limit.lua b/codes/java-distributed/java-rate-limit/src/main/resources/scripts/fixed_window_rate_limit.lua
new file mode 100644
index 00000000..e0c9ad00
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/resources/scripts/fixed_window_rate_limit.lua
@@ -0,0 +1,21 @@
+-- 缓存 Key
+local key = KEYS[1]
+-- 访问请求数
+local permits = tonumber(ARGV[1])
+-- 过期时间
+local seconds = tonumber(ARGV[2])
+-- 限流阈值
+local limit = tonumber(ARGV[3])
+
+-- 获取统计值
+local count = tonumber(redis.call('GET', key) or "0")
+
+if count + permits > limit then
+ -- 请求拒绝
+ return -1
+else
+ -- 请求通过
+ redis.call('INCRBY', key, permits)
+ redis.call('EXPIRE', key, seconds)
+ return count + permits
+end
\ No newline at end of file
diff --git a/codes/java-distributed/java-rate-limit/src/main/resources/scripts/token_bucket_rate_limit.lua b/codes/java-distributed/java-rate-limit/src/main/resources/scripts/token_bucket_rate_limit.lua
new file mode 100644
index 00000000..541d70c9
--- /dev/null
+++ b/codes/java-distributed/java-rate-limit/src/main/resources/scripts/token_bucket_rate_limit.lua
@@ -0,0 +1,39 @@
+local tokenKey = KEYS[1]
+local timeKey = KEYS[2]
+
+-- 申请令牌数
+local permits = tonumber(ARGV[1])
+-- QPS
+local qps = tonumber(ARGV[2])
+-- 桶的容量
+local capacity = tonumber(ARGV[3])
+-- 当前时间(单位:毫秒)
+local nowMillis = tonumber(ARGV[4])
+-- 填满令牌桶所需要的时间
+local fillTime = capacity / qps
+local ttl = math.min(capacity, math.floor(fillTime * 2))
+
+local currentTokenNum = tonumber(redis.call("GET", tokenKey))
+if currentTokenNum == nil then
+ currentTokenNum = capacity
+end
+
+local endTimeMillis = tonumber(redis.call("GET", timeKey))
+if endTimeMillis == nil then
+ endTimeMillis = 0
+end
+
+local gap = nowMillis - endTimeMillis
+local newTokenNum = math.max(0, gap * qps / 1000)
+local currentTokenNum = math.min(capacity, currentTokenNum + newTokenNum)
+
+if currentTokenNum < permits then
+ -- 请求拒绝
+ return -1
+else
+ -- 请求通过
+ local finalTokenNum = currentTokenNum - permits
+ redis.call("SETEX", tokenKey, ttl, finalTokenNum)
+ redis.call("SETEX", timeKey, ttl, nowMillis)
+ return finalTokenNum
+end
diff --git a/codes/java-distributed/java-task/pom.xml b/codes/java-distributed/java-task/pom.xml
new file mode 100644
index 00000000..8d7cc462
--- /dev/null
+++ b/codes/java-distributed/java-task/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+
+
+ io.github.dunwu.distributed
+ java-distributed
+ 1.0.0
+
+
+ io.github.dunwu.distributed
+ java-task
+ 1.0.0
+ jar
+
+
+ UTF-8
+ 1.8
+ ${java.version}
+ ${java.version}
+
+
+
+
+ cn.hutool
+ hutool-all
+
+
+ org.projectlombok
+ lombok
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+ true
+
+
+
diff --git a/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/DelayQueueExample.java b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/DelayQueueExample.java
new file mode 100644
index 00000000..d510eed1
--- /dev/null
+++ b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/DelayQueueExample.java
@@ -0,0 +1,52 @@
+package io.github.dunwu.local.task;
+
+import cn.hutool.core.date.DateUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Date;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.DelayQueue;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class DelayQueueExample {
+
+ public static void main(String[] args) throws InterruptedException {
+ BlockingQueue delayQueue = new DelayQueue<>();
+ long now = System.currentTimeMillis();
+ delayQueue.put(new SampleTask(now + 1000));
+ delayQueue.put(new SampleTask(now + 2000));
+ delayQueue.put(new SampleTask(now + 3000));
+ for (int i = 0; i < 3; i++) {
+ log.info("task 执行时间:{}", DateUtil.format(new Date(delayQueue.take().getTime()), "yyyy-MM-dd HH:mm:ss"));
+ }
+ }
+
+ static class SampleTask implements Delayed {
+
+ long time;
+
+ public SampleTask(long time) {
+ this.time = time;
+ }
+
+ public long getTime() {
+ return time;
+ }
+
+ @Override
+ public int compareTo(Delayed o) {
+ return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
+ }
+
+ @Override
+ public long getDelay(TimeUnit unit) {
+ return unit.convert(time - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
+ }
+
+ }
+
+}
+
+
diff --git a/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/ScheduledExecutorServiceExample.java b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/ScheduledExecutorServiceExample.java
new file mode 100644
index 00000000..78e8f5bd
--- /dev/null
+++ b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/ScheduledExecutorServiceExample.java
@@ -0,0 +1,37 @@
+package io.github.dunwu.local.task;
+
+import cn.hutool.core.date.DateUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Date;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class ScheduledExecutorServiceExample {
+
+ public static void main(String[] args) {
+ // 创建一个 ScheduledExecutorService 对象,它将使用一个线程池来执行任务
+ ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+
+ // 创建一个 Runnable 对象,这个任务将在 2 秒后执行,并且每 1 秒重复执行一次
+ Runnable task = () -> {
+ log.info("task 执行时间:{}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
+ };
+
+ // 安排任务在 2 秒后执行,并且每 1 秒重复执行一次
+ executor.scheduleAtFixedRate(task, 2, 1, TimeUnit.SECONDS);
+
+ // 主线程等待 10 秒后结束
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ // 关闭 executor,这将停止所有正在执行的任务,并拒绝新任务的提交
+ executor.shutdown();
+ }
+
+}
diff --git a/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/TimerExample.java b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/TimerExample.java
new file mode 100644
index 00000000..ce1d7756
--- /dev/null
+++ b/codes/java-distributed/java-task/src/main/java/io/github/dunwu/local/task/TimerExample.java
@@ -0,0 +1,39 @@
+package io.github.dunwu.local.task;
+
+import cn.hutool.core.date.DateUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+@Slf4j
+public class TimerExample {
+
+ public static void main(String[] args) {
+ // 创建一个 Timer 对象
+ Timer timer = new Timer();
+
+ // 创建一个 TimerTask 对象,这个任务将在 2 秒后执行,并且每 1 秒重复执行一次
+ TimerTask task = new TimerTask() {
+ @Override
+ public void run() {
+ log.info("task 执行时间:{}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
+ }
+ };
+
+ // 安排任务在 2 秒后执行,并且每 1 秒重复执行一次
+ timer.schedule(task, 2000, 1000);
+
+ // 主线程等待 10 秒后结束
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ // 取消定时器和所有已安排的任务
+ timer.cancel();
+ }
+
+}
diff --git a/codes/java-distributed/pom.xml b/codes/java-distributed/pom.xml
index 35fd5860..aa88d15d 100644
--- a/codes/java-distributed/pom.xml
+++ b/codes/java-distributed/pom.xml
@@ -3,15 +3,52 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- io.github.dunwu.javatech
+ io.github.dunwu.distributed
java-distributed
1.0.0
pom
- JAVA-DISTRIBUTED
- JAVA-DISTRIBUTED 示例源码
java-load-balance
+ java-rate-limit
+ java-distributed-id
+ java-task
+
+
+
+ org.apache.zookeeper
+ zookeeper
+ 3.9.2
+
+
+ org.apache.curator
+ curator-recipes
+ 4.3.0
+
+
+ redis.clients
+ jedis
+ 5.1.0
+
+
+ cn.hutool
+ hutool-all
+ 5.8.34
+
+
+ org.projectlombok
+ lombok
+ 1.18.30
+
+
+ ch.qos.logback
+ logback-classic
+ 1.4.12
+ true
+
+
+
+
diff --git a/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/service/HelloService.java b/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/service/HelloService.java
index b7c9d1de..75d9b577 100644
--- a/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/service/HelloService.java
+++ b/codes/javatech/javatech-server/src/main/java/io/github/dunwu/javatech/service/HelloService.java
@@ -3,7 +3,7 @@
import org.springframework.stereotype.Service;
/**
- * @author 11123558
+ * @author Zhang Peng
* @date 2022-07-28
*/
@Service
diff --git a/codes/javatech/javatech-server/src/test/java/io/github/dunwu/javatech/HelloControllerTests.java b/codes/javatech/javatech-server/src/test/java/io/github/dunwu/javatech/HelloControllerTests.java
index 3e16d05e..946e65de 100644
--- a/codes/javatech/javatech-server/src/test/java/io/github/dunwu/javatech/HelloControllerTests.java
+++ b/codes/javatech/javatech-server/src/test/java/io/github/dunwu/javatech/HelloControllerTests.java
@@ -10,7 +10,7 @@
/**
* 单元测试
- * @author 11123558
+ * @author Zhang Peng
* @date 2022-07-28
*/
@RunWith(SpringJUnit4ClassRunner.class)
diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js
index 4c6f199d..6bba8f05 100644
--- a/docs/.vuepress/config.js
+++ b/docs/.vuepress/config.js
@@ -14,48 +14,55 @@ module.exports = {
['link', { rel: 'icon', href: '/img/favicon.ico' }], //favicons,资源放在public文件夹
['meta', { name: 'keywords', content: 'vuepress,theme,blog,vdoing' }],
['meta', { name: 'theme-color', content: '#11a8cd' }], // 移动浏览器主题颜色
+
+ ['meta', { name: 'wwads-cn-verify', content: 'mxqWx62nfQQ9ocT4e5DzISHzOWyF4s' }], // 广告相关,你可以去掉
+ ['script', { src: 'https://cdn.wwads.cn/js/makemoney.js', type: 'text/javascript' }] // 广告相关,你可以去掉
],
markdown: {
// lineNumbers: true,
extractHeaders: ['h2', 'h3', 'h4', 'h5', 'h6'], // 提取标题到侧边栏的级别,默认['h2', 'h3']
externalLinks: {
target: '_blank',
- rel: 'noopener noreferrer',
- },
+ rel: 'noopener noreferrer'
+ }
},
// 主题配置
themeConfig: {
nav: [
+ { text: '首页', link: '/' },
+ { text: 'JavaEE', link: '/01.Java/02.JavaEE/' },
{
- text: 'JavaEE',
+ text: 'Java软件',
+ link: '/01.Java/11.软件/',
items: [
- { text: 'JavaWeb', link: '/02.JavaEE/01.JavaWeb/' },
- { text: '服务器', link: '/02.JavaEE/02.服务器/' },
- ],
+ { text: 'Java 构建', link: '/01.Java/11.软件/01.构建/' },
+ { text: 'Java IDE', link: '/01.Java/11.软件/02.IDE/' },
+ { text: 'Java 监控诊断', link: '/01.Java/11.软件/03.监控诊断/' }
+ ]
},
{
- text: 'Java软件',
- link: '/11.软件/',
+ text: 'Java工具',
+ link: '/01.Java/12.工具/',
items: [
- { text: 'Java构建', link: '/11.软件/01.构建/' },
- { text: 'Java IDE', link: '/11.软件/02.IDE/' },
- { text: 'Java监控诊断', link: '/11.软件/03.监控诊断/' },
- ],
+ { text: 'Java IO 工具', link: '/01.Java/12.工具/01.IO/' },
+ { text: 'JavaBean 工具', link: '/01.Java/12.工具/02.JavaBean/' },
+ { text: 'Java 模板引擎', link: '/01.Java/12.工具/03.模板引擎/' },
+ { text: 'Java 测试工具', link: '/01.Java/12.工具/04.测试/' }
+ ]
},
- { text: 'Java工具', link: '/12.工具/' },
- { text: 'Java框架', link: '/13.框架/' },
- { text: 'Java中间件', link: '/14.中间件/' },
+ { text: 'Java框架', link: '/01.Java/13.框架/' },
+ { text: 'Java中间件', link: '/01.Java/14.中间件/' },
{
text: '✨ Java系列',
ariaLabel: 'Java',
items: [
{ text: 'Java 教程 📚', link: 'https://dunwu.github.io/java-tutorial/', target: '_blank' },
- { text: 'JavaCore 教程 📚', link: 'https://dunwu.github.io/javacore/', target: '_blank' },
- ],
- },
+ { text: 'JavaCore 教程 📚', link: 'https://dunwu.github.io/javacore/', target: '_blank' }
+ ]
+ }
],
sidebarDepth: 2, // 侧边栏显示深度,默认1,最大2(显示到h3标题)
- logo: 'https://raw.githubusercontent.com/dunwu/images/dev/common/dunwu-logo.png', // 导航栏logo
+ logo: 'https://raw.githubusercontent.com/dunwu/images/master/common/dunwu-logo.png', // 导航栏logo
repo: 'dunwu/java-tutorial', // 导航栏右侧生成Github链接
searchMaxSuggestions: 10, // 搜索结果显示最大数
lastUpdated: '上次更新', // 更新的时间,及前缀文字 string | boolean (取值为git提交时间)
@@ -65,12 +72,13 @@ module.exports = {
editLinkText: '📝 帮助改善此页面!',
// 以下配置是Vdoing主题改动的和新增的配置
- sidebar: { mode: 'structuring', collapsable: false }, // 侧边栏 'structuring' | { mode: 'structuring', collapsable: Boolean} | 'auto' | 自定义 温馨提示:目录页数据依赖于结构化的侧边栏数据,如果你不设置为'structuring',将无法使用目录页
+ sidebar: { mode: 'structuring', collapsable: true }, // 侧边栏 'structuring' | { mode: 'structuring', collapsable:
+ // Boolean} | 'auto' | 自定义 温馨提示:目录页数据依赖于结构化的侧边栏数据,如果你不设置为'structuring',将无法使用目录页
- // sidebarOpen: false, // 初始状态是否打开侧边栏,默认true
+ sidebarOpen: true, // 初始状态是否打开侧边栏,默认true
updateBar: {
// 最近更新栏
- showToArticle: true, // 显示到文章页底部,默认true
+ showToArticle: true // 显示到文章页底部,默认true
// moreArticle: '/archives' // “更多文章”跳转的页面,默认'/archives'
},
// titleBadge: false, // 文章标题前的图标是否显示,默认true
@@ -95,7 +103,7 @@ module.exports = {
author: {
// 文章默认的作者信息,可在md文件中单独配置此信息 String | {name: String, href: String}
name: 'dunwu', // 必需
- href: 'https://github.com/dunwu', // 可选的
+ href: 'https://github.com/dunwu' // 可选的
},
social: {
// 社交图标,显示于博主信息栏和页脚栏
@@ -104,21 +112,21 @@ module.exports = {
{
iconClass: 'icon-youjian',
title: '发邮件',
- link: 'mailto:forbreak@163.com',
+ link: 'mailto:forbreak@163.com'
},
{
iconClass: 'icon-github',
title: 'GitHub',
- link: 'https://github.com/dunwu',
- },
- ],
+ link: 'https://github.com/dunwu'
+ }
+ ]
},
footer: {
// 页脚信息
createYear: 2019, // 博客创建年份
- copyrightInfo: '钝悟(dunwu) | CC-BY-SA-4.0', // 博客版权信息,支持a标签
+ copyrightInfo: '钝悟(dunwu) | CC-BY-SA-4.0' // 博客版权信息,支持a标签
},
- htmlModules,
+ htmlModules
},
// 插件
@@ -128,8 +136,8 @@ module.exports = {
{
// 鼠标点击爱心特效
color: '#11a8cd', // 爱心颜色,默认随机色
- excludeClassName: 'theme-vdoing-content', // 要排除元素的class, 默认空''
- },
+ excludeClassName: 'theme-vdoing-content' // 要排除元素的class, 默认空''
+ }
],
['fulltext-search'], // 全文搜索
@@ -159,8 +167,8 @@ module.exports = {
copySelector: ['div[class*="language-"] pre', 'div[class*="aside-code"] aside'], // String or Array
copyMessage: '复制成功', // default is 'Copy successfully and then paste it for use.'
duration: 1000, // prompt message display time.
- showInMobile: false, // whether to display on the mobile side, default: false.
- },
+ showInMobile: false // whether to display on the mobile side, default: false.
+ }
],
[
'demo-block',
@@ -172,18 +180,18 @@ module.exports = {
// vue: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js', // 在线示例中的vue依赖
jsfiddle: false, // 是否显示 jsfiddle 链接
codepen: true, // 是否显示 codepen 链接
- horizontal: false, // 是否展示为横向样式
- },
- },
+ horizontal: false // 是否展示为横向样式
+ }
+ }
],
[
'vuepress-plugin-zooming', // 放大图片
{
selector: '.theme-vdoing-content img:not(.no-zoom)',
options: {
- bgColor: 'rgba(0,0,0,0.6)',
- },
- },
+ bgColor: 'rgba(0,0,0,0.6)'
+ }
+ }
],
[
'@vuepress/last-updated', // "上次更新"时间格式
@@ -191,11 +199,11 @@ module.exports = {
transformer: (timestamp, lang) => {
const dayjs = require('dayjs') // https://day.js.org/
return dayjs(timestamp).format('YYYY/MM/DD, HH:mm:ss')
- },
- },
- ],
+ }
+ }
+ ]
],
// 监听文件变化并重新构建
- extraWatchFiles: ['.vuepress/config.js', '.vuepress/config/htmlModules.js'],
+ extraWatchFiles: ['.vuepress/config.js', '.vuepress/config/htmlModules.js']
}
diff --git a/docs/.vuepress/config/baiduCode.js b/docs/.vuepress/config/baiduCode.js
index 9dc5fc1e..b0c50903 100644
--- a/docs/.vuepress/config/baiduCode.js
+++ b/docs/.vuepress/config/baiduCode.js
@@ -1 +1 @@
-module.exports = '';
+module.exports = ''
diff --git a/docs/.vuepress/config/htmlModules.js b/docs/.vuepress/config/htmlModules.js
index 6ba3782b..fc0a47eb 100644
--- a/docs/.vuepress/config/htmlModules.js
+++ b/docs/.vuepress/config/htmlModules.js
@@ -20,20 +20,37 @@
module.exports = {
// 万维广告
- pageB: `
-
-
- `,
+ // pageT: `
+ //
+ //
+ // `,
windowRB: `
-
"
- const wwadsEl = document.getElementsByClassName('wwads-cn')
- const wwadsContentEl = document.querySelector('.wwads-content')
+ const h = "
";
+ const wwadsEl = document.getElementsByClassName("wwads-cn");
+ const wwadsContentEl = document.querySelector('.wwads-content');
if (wwadsEl[0] && !wwadsContentEl) {
- wwadsEl[0].innerHTML = h
+ wwadsEl[0].innerHTML = h;
}
-}
+};
//check document ready
function docReady(t) {
- 'complete' === document.readyState || 'interactive' === document.readyState
- ? setTimeout(t, 1)
- : document.addEventListener('DOMContentLoaded', t)
-}
-
-// 集成 Gitalk 评论插件
-function integrateGitalk(router) {
- const linkGitalk = document.createElement('link')
- linkGitalk.href = 'https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css'
- linkGitalk.rel = 'stylesheet'
- document.body.appendChild(linkGitalk)
- const scriptGitalk = document.createElement('script')
- scriptGitalk.src = 'https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js'
- document.body.appendChild(scriptGitalk)
-
- router.afterEach((to) => {
- if (scriptGitalk.onload) {
- loadGitalk(to)
- } else {
- scriptGitalk.onload = () => {
- loadGitalk(to)
- }
- }
- })
-
- function loadGitalk(to) {
- let commentsContainer = document.getElementById('gitalk-container')
- if (!commentsContainer) {
- commentsContainer = document.createElement('div')
- commentsContainer.id = 'gitalk-container'
- commentsContainer.classList.add('content')
- }
- const $page = document.querySelector('.page')
- if ($page) {
- $page.appendChild(commentsContainer)
- if (typeof Gitalk !== 'undefined' && Gitalk instanceof Function) {
- renderGitalk(to.fullPath)
- }
- }
- }
- function renderGitalk(fullPath) {
- console.info(fullPath)
- const gitalk = new Gitalk({
- clientID: '1ba9606d18aec7c070d4',
- clientSecret: '57c7e5e3611840efe117ccbad4d87fb60cb364cc', // come from github development
- repo: 'java-tutorial',
- owner: 'dunwu',
- admin: ['dunwu'],
- id: 'comment',
- distractionFreeMode: false,
- language: 'zh-CN',
- })
- gitalk.render('gitalk-container')
- }
+ "complete" === document.readyState ||
+ "interactive" === document.readyState
+ ? setTimeout(t, 1)
+ : document.addEventListener("DOMContentLoaded", t);
}
diff --git a/docs/.vuepress/plugins/love-me/index.js b/docs/.vuepress/plugins/love-me/index.js
index 67f5ea9c..2851beb0 100644
--- a/docs/.vuepress/plugins/love-me/index.js
+++ b/docs/.vuepress/plugins/love-me/index.js
@@ -7,6 +7,6 @@ const LoveMyPlugin = (options = {}) => ({
const EXCLUDECLASS = options.excludeClassName || ''
return { COLOR, EXCLUDECLASS }
},
- enhanceAppFiles: [path.resolve(__dirname, 'love-me.js')],
+ enhanceAppFiles: [path.resolve(__dirname, 'love-me.js')]
})
module.exports = LoveMyPlugin
diff --git a/docs/.vuepress/plugins/love-me/love-me.js b/docs/.vuepress/plugins/love-me/love-me.js
index f93855e6..5c0369ac 100644
--- a/docs/.vuepress/plugins/love-me/love-me.js
+++ b/docs/.vuepress/plugins/love-me/love-me.js
@@ -1,62 +1,89 @@
export default () => {
- if (typeof window !== "undefined") {
- (function(e, t, a) {
- function r() {
- for (var e = 0; e < s.length; e++) s[e].alpha <= 0 ? (t.body.removeChild(s[e].el), s.splice(e, 1)) : (s[e].y--, s[e].scale += .004, s[e].alpha -= .013, s[e].el.style.cssText = "left:" + s[e].x + "px;top:" + s[e].y + "px;opacity:" + s[e].alpha + ";transform:scale(" + s[e].scale + "," + s[e].scale + ") rotate(45deg);background:" + s[e].color + ";z-index:99999");
- requestAnimationFrame(r)
- }
- function n() {
- var t = "function" == typeof e.onclick && e.onclick;
-
- e.onclick = function(e) {
- // 过滤指定元素
- let mark = true;
- EXCLUDECLASS && e.path && e.path.forEach((item) =>{
- if(item.nodeType === 1) {
- typeof item.className === 'string' && item.className.indexOf(EXCLUDECLASS) > -1 ? mark = false : ''
- }
- })
-
- if(mark) {
- t && t(),
- o(e)
+ if (typeof window !== 'undefined') {
+ ;(function (e, t, a) {
+ function r() {
+ for (var e = 0; e < s.length; e++)
+ s[e].alpha <= 0
+ ? (t.body.removeChild(s[e].el), s.splice(e, 1))
+ : (s[e].y--,
+ (s[e].scale += 0.004),
+ (s[e].alpha -= 0.013),
+ (s[e].el.style.cssText =
+ 'left:' +
+ s[e].x +
+ 'px;top:' +
+ s[e].y +
+ 'px;opacity:' +
+ s[e].alpha +
+ ';transform:scale(' +
+ s[e].scale +
+ ',' +
+ s[e].scale +
+ ') rotate(45deg);background:' +
+ s[e].color +
+ ';z-index:99999'))
+ requestAnimationFrame(r)
+ }
+ function n() {
+ var t = 'function' == typeof e.onclick && e.onclick
+
+ e.onclick = function (e) {
+ // 过滤指定元素
+ let mark = true
+ EXCLUDECLASS &&
+ e.path &&
+ e.path.forEach((item) => {
+ if (item.nodeType === 1) {
+ typeof item.className === 'string' && item.className.indexOf(EXCLUDECLASS) > -1 ? (mark = false) : ''
}
- }
- }
- function o(e) {
- var a = t.createElement("div");
- a.className = "heart",
- s.push({
- el: a,
- x: e.clientX - 5,
- y: e.clientY - 5,
- scale: 1,
- alpha: 1,
- color: COLOR
- }),
- t.body.appendChild(a)
+ })
+
+ if (mark) {
+ t && t(), o(e)
+ }
}
- function i(e) {
- var a = t.createElement("style");
- a.type = "text/css";
- try {
- a.appendChild(t.createTextNode(e))
- } catch(t) {
- a.styleSheet.cssText = e
- }
- t.getElementsByTagName("head")[0].appendChild(a)
+ }
+ function o(e) {
+ var a = t.createElement('div')
+ ;(a.className = 'heart'),
+ s.push({
+ el: a,
+ x: e.clientX - 5,
+ y: e.clientY - 5,
+ scale: 1,
+ alpha: 1,
+ color: COLOR
+ }),
+ t.body.appendChild(a)
+ }
+ function i(e) {
+ var a = t.createElement('style')
+ a.type = 'text/css'
+ try {
+ a.appendChild(t.createTextNode(e))
+ } catch (t) {
+ a.styleSheet.cssText = e
}
- // function c() {
- // return "rgb(" + ~~ (255 * Math.random()) + "," + ~~ (255 * Math.random()) + "," + ~~ (255 * Math.random()) + ")"
- // }
- var s = [];
- e.requestAnimationFrame = e.requestAnimationFrame || e.webkitRequestAnimationFrame || e.mozRequestAnimationFrame || e.oRequestAnimationFrame || e.msRequestAnimationFrame ||
- function(e) {
- setTimeout(e, 1e3 / 60)
- },
- i(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"),
+ t.getElementsByTagName('head')[0].appendChild(a)
+ }
+ // function c() {
+ // return "rgb(" + ~~ (255 * Math.random()) + "," + ~~ (255 * Math.random()) + "," + ~~ (255 * Math.random()) + ")"
+ // }
+ var s = []
+ ;(e.requestAnimationFrame =
+ e.requestAnimationFrame ||
+ e.webkitRequestAnimationFrame ||
+ e.mozRequestAnimationFrame ||
+ e.oRequestAnimationFrame ||
+ e.msRequestAnimationFrame ||
+ function (e) {
+ setTimeout(e, 1e3 / 60)
+ }),
+ i(
+ ".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"
+ ),
n(),
r()
})(window, document)
}
-}
\ No newline at end of file
+}
diff --git a/docs/.vuepress/public/favicon.ico b/docs/.vuepress/public/favicon.ico
new file mode 100644
index 00000000..51e9bfa0
Binary files /dev/null and b/docs/.vuepress/public/favicon.ico differ
diff --git a/docs/.vuepress/public/img/EB-logo.png b/docs/.vuepress/public/img/EB-logo.png
deleted file mode 100644
index 8e1d5674..00000000
Binary files a/docs/.vuepress/public/img/EB-logo.png and /dev/null differ
diff --git a/docs/.vuepress/public/img/bg.jpeg b/docs/.vuepress/public/img/bg.jpeg
deleted file mode 100644
index 85e53e7d..00000000
Binary files a/docs/.vuepress/public/img/bg.jpeg and /dev/null differ
diff --git a/docs/.vuepress/public/img/bg.jpg b/docs/.vuepress/public/img/bg.jpg
deleted file mode 100644
index f093e799..00000000
Binary files a/docs/.vuepress/public/img/bg.jpg and /dev/null differ
diff --git "a/docs/.vuepress/public/img/gif/\347\214\2531.gif" "b/docs/.vuepress/public/img/gif/\347\214\2531.gif"
deleted file mode 100644
index e84d8a28..00000000
Binary files "a/docs/.vuepress/public/img/gif/\347\214\2531.gif" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/gif/\347\214\2532.gif" "b/docs/.vuepress/public/img/gif/\347\214\2532.gif"
deleted file mode 100644
index 28114599..00000000
Binary files "a/docs/.vuepress/public/img/gif/\347\214\2532.gif" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/gif/\347\214\2533.gif" "b/docs/.vuepress/public/img/gif/\347\214\2533.gif"
deleted file mode 100644
index 894372d9..00000000
Binary files "a/docs/.vuepress/public/img/gif/\347\214\2533.gif" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/gif/\347\214\2534.gif" "b/docs/.vuepress/public/img/gif/\347\214\2534.gif"
deleted file mode 100644
index 7b991309..00000000
Binary files "a/docs/.vuepress/public/img/gif/\347\214\2534.gif" and /dev/null differ
diff --git a/docs/.vuepress/public/img/panda-waving.png b/docs/.vuepress/public/img/panda-waving.png
deleted file mode 100644
index 20246c60..00000000
Binary files a/docs/.vuepress/public/img/panda-waving.png and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\346\200\235\347\273\264\345\257\274\345\233\276.png" "b/docs/.vuepress/public/img/png/\346\200\235\347\273\264\345\257\274\345\233\276.png"
deleted file mode 100644
index 819ef70b..00000000
Binary files "a/docs/.vuepress/public/img/png/\346\200\235\347\273\264\345\257\274\345\233\276.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\346\225\260\346\215\256\345\272\223.png" "b/docs/.vuepress/public/img/png/\346\225\260\346\215\256\345\272\223.png"
deleted file mode 100644
index 4d13c3f2..00000000
Binary files "a/docs/.vuepress/public/img/png/\346\225\260\346\215\256\345\272\223.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\346\225\260\346\215\256\347\273\223\346\236\204.png" "b/docs/.vuepress/public/img/png/\346\225\260\346\215\256\347\273\223\346\236\204.png"
deleted file mode 100644
index 1bafe966..00000000
Binary files "a/docs/.vuepress/public/img/png/\346\225\260\346\215\256\347\273\223\346\236\204.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\346\234\215\345\212\241\345\231\250.png" "b/docs/.vuepress/public/img/png/\346\234\215\345\212\241\345\231\250.png"
deleted file mode 100644
index 4127eb56..00000000
Binary files "a/docs/.vuepress/public/img/png/\346\234\215\345\212\241\345\231\250.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\346\234\272\345\231\250\345\255\246\344\271\240.png" "b/docs/.vuepress/public/img/png/\346\234\272\345\231\250\345\255\246\344\271\240.png"
deleted file mode 100644
index 081c2b88..00000000
Binary files "a/docs/.vuepress/public/img/png/\346\234\272\345\231\250\345\255\246\344\271\240.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\347\256\227\346\263\225.png" "b/docs/.vuepress/public/img/png/\347\256\227\346\263\225.png"
deleted file mode 100644
index 92fef3f6..00000000
Binary files "a/docs/.vuepress/public/img/png/\347\256\227\346\263\225.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\347\263\273\347\273\237.png" "b/docs/.vuepress/public/img/png/\347\263\273\347\273\237.png"
deleted file mode 100644
index 87f0de0a..00000000
Binary files "a/docs/.vuepress/public/img/png/\347\263\273\347\273\237.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\347\263\273\347\273\237\345\210\206\346\236\220.png" "b/docs/.vuepress/public/img/png/\347\263\273\347\273\237\345\210\206\346\236\220.png"
deleted file mode 100644
index 208e2597..00000000
Binary files "a/docs/.vuepress/public/img/png/\347\263\273\347\273\237\345\210\206\346\236\220.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\347\274\226\347\250\213.png" "b/docs/.vuepress/public/img/png/\347\274\226\347\250\213.png"
deleted file mode 100644
index a8bca769..00000000
Binary files "a/docs/.vuepress/public/img/png/\347\274\226\347\250\213.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\347\275\221\347\273\234\346\212\200\346\234\257.png" "b/docs/.vuepress/public/img/png/\347\275\221\347\273\234\346\212\200\346\234\257.png"
deleted file mode 100644
index f81edb71..00000000
Binary files "a/docs/.vuepress/public/img/png/\347\275\221\347\273\234\346\212\200\346\234\257.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.png" "b/docs/.vuepress/public/img/png/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.png"
deleted file mode 100644
index 63a1819f..00000000
Binary files "a/docs/.vuepress/public/img/png/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\350\275\257\344\273\266\345\274\200\345\217\221.png" "b/docs/.vuepress/public/img/png/\350\275\257\344\273\266\345\274\200\345\217\221.png"
deleted file mode 100644
index 72c5e852..00000000
Binary files "a/docs/.vuepress/public/img/png/\350\275\257\344\273\266\345\274\200\345\217\221.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\351\235\242\345\220\221\345\257\271\350\261\241.png" "b/docs/.vuepress/public/img/png/\351\235\242\345\220\221\345\257\271\350\261\241.png"
deleted file mode 100644
index cd13fa3c..00000000
Binary files "a/docs/.vuepress/public/img/png/\351\235\242\345\220\221\345\257\271\350\261\241.png" and /dev/null differ
diff --git "a/docs/.vuepress/public/img/png/\351\241\271\347\233\256\347\256\241\347\220\206.png" "b/docs/.vuepress/public/img/png/\351\241\271\347\233\256\347\256\241\347\220\206.png"
deleted file mode 100644
index 0467abd5..00000000
Binary files "a/docs/.vuepress/public/img/png/\351\241\271\347\233\256\347\256\241\347\220\206.png" and /dev/null differ
diff --git a/docs/.vuepress/public/img/python.png b/docs/.vuepress/public/img/python.png
deleted file mode 100644
index c3ddebeb..00000000
Binary files a/docs/.vuepress/public/img/python.png and /dev/null differ
diff --git a/docs/.vuepress/public/img/ui.png b/docs/.vuepress/public/img/ui.png
deleted file mode 100644
index 617c56d7..00000000
Binary files a/docs/.vuepress/public/img/ui.png and /dev/null differ
diff --git a/docs/.vuepress/public/img/web.png b/docs/.vuepress/public/img/web.png
deleted file mode 100644
index 0a6e27c4..00000000
Binary files a/docs/.vuepress/public/img/web.png and /dev/null differ
diff --git a/docs/.vuepress/public/markmap/01.html b/docs/.vuepress/public/markmap/01.html
index c55f2d03..c4e0bdbc 100644
--- a/docs/.vuepress/public/markmap/01.html
+++ b/docs/.vuepress/public/markmap/01.html
@@ -1,25 +1,113 @@
-
-
-
-
-Markmap
-
-
-
-
-
-
-
+
+
+
+
+ Markmap
+
+
+
+
+
+
+
+
diff --git "a/docs/02.JavaEE/01.JavaWeb/01.JavaWeb\344\271\213Servlet\346\214\207\345\215\227.md" "b/docs/01.Java/02.JavaEE/01.JavaWeb/01.JavaWeb\344\271\213Servlet\346\214\207\345\215\227.md"
similarity index 99%
rename from "docs/02.JavaEE/01.JavaWeb/01.JavaWeb\344\271\213Servlet\346\214\207\345\215\227.md"
rename to "docs/01.Java/02.JavaEE/01.JavaWeb/01.JavaWeb\344\271\213Servlet\346\214\207\345\215\227.md"
index c49ed4f2..2133814e 100644
--- "a/docs/02.JavaEE/01.JavaWeb/01.JavaWeb\344\271\213Servlet\346\214\207\345\215\227.md"
+++ "b/docs/01.Java/02.JavaEE/01.JavaWeb/01.JavaWeb\344\271\213Servlet\346\214\207\345\215\227.md"
@@ -1,16 +1,16 @@
---
title: JavaWeb 之 Servlet 指南
-categories:
- - 编程
+date: 2020-08-24 19:41:46
+order: 01
+categories:
- Java
+ - JavaEE
- JavaWeb
-tags:
+tags:
- Java
- JavaWeb
- Servlet
-abbrlink: 2ce8dedd
-date: 2020-08-24 19:41:46
-permalink: /pages/be093b/
+permalink: /pages/e98894/
---
# JavaWeb 之 Servlet 指南
@@ -310,4 +310,4 @@ Apache Tomcat/5.5.29
## 参考资料
- [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
-- [Java Web 整合开发王者归来](https://book.douban.com/subject/4189495/)
+- [Java Web 整合开发王者归来](https://book.douban.com/subject/4189495/)
\ No newline at end of file
diff --git "a/docs/02.JavaEE/01.JavaWeb/02.JavaWeb\344\271\213Jsp\346\214\207\345\215\227.md" "b/docs/01.Java/02.JavaEE/01.JavaWeb/02.JavaWeb\344\271\213Jsp\346\214\207\345\215\227.md"
similarity index 95%
rename from "docs/02.JavaEE/01.JavaWeb/02.JavaWeb\344\271\213Jsp\346\214\207\345\215\227.md"
rename to "docs/01.Java/02.JavaEE/01.JavaWeb/02.JavaWeb\344\271\213Jsp\346\214\207\345\215\227.md"
index f0c28076..32b8ab7c 100644
--- "a/docs/02.JavaEE/01.JavaWeb/02.JavaWeb\344\271\213Jsp\346\214\207\345\215\227.md"
+++ "b/docs/01.Java/02.JavaEE/01.JavaWeb/02.JavaWeb\344\271\213Jsp\346\214\207\345\215\227.md"
@@ -1,16 +1,16 @@
---
title: JavaWeb 之 Jsp 指南
-categories:
- - 编程
+date: 2020-02-07 23:04:47
+order: 02
+categories:
- Java
+ - JavaEE
- JavaWeb
-tags:
+tags:
- Java
- JavaWeb
- JSP
-abbrlink: 339b3115
-date: 2020-02-07 23:04:47
-permalink: /pages/6bbb16/
+permalink: /pages/8cc787/
---
# JavaWeb 之 Jsp 指南
@@ -21,7 +21,7 @@ permalink: /pages/6bbb16/
`JSP`全称`Java Server Pages`,是一种动态网页开发技术。
-它使用 JSP 标签在 HTML 网页中插入 Java 代码。标签通常以`<%`开头以`%>`结束。
+它使用 JSP 标签在 HTML 网页中插入 Java 代码。标签通常以 `<%` 开头以 `%>` 结束。
JSP 是一种 Java servlet,主要用于实现 Java web 应用程序的用户界面部分。网页开发者们通过结合 HTML 代码、XHTML 代码、XML 元素以及嵌入 JSP 操作和命令来编写 JSP。
@@ -334,14 +334,14 @@ pageEncoding="UTF-8"%>
不同情况下使用注释的语法规则:
-| **语法** | 描述 |
-| ---------------- | ----------------------------------------------------- |
-| `<%-- 注释 --%>` | JSP 注释,注释内容不会被发送至浏览器甚至不会被编译 |
+| **语法** | 描述 |
+| ---------------- |-------------------------------|
+| `<%-- 注释 --%>` | JSP 注释,注释内容不会被发送至浏览器甚至不会被编译 |
| `` | HTML 注释,通过浏览器查看网页源代码时可以看见注释内容 |
-| `<%` | 代表静态 <%常量 |
-| `%>` | 代表静态 %> 常量 |
-| `'` | 在属性中使用的单引号 |
-| `"` | 在属性中使用的双引号 |
+| `<%` | 代表静态 `<%` 常量 |
+| `%>` | 代表静态 `%>` 常量 |
+| `'` | 在属性中使用的单引号 |
+| `"` | 在属性中使用的双引号 |
### 控制语句
@@ -471,23 +471,23 @@ JSP 支持所有 Java 逻辑和算术运算符。
下表罗列出了 JSP 常见运算符,优先级从高到底:
-| **类别** | **操作符** | **结合性** |
-| --------- | -------------------------------- | ---------- | ------ | ------ |
-| 后缀 | `() [] .` (点运算符) | 左到右 |
-| 一元 | `++ - - ! ~` | 右到左 |
-| 可乘性 | `* / %` | 左到右 |
-| 可加性 | `+ -` | 左到右 |
-| 移位 | `>> >>> <<` | 左到右 |
-| 关系 | `> >= < <=` | 左到右 |
-| 相等/不等 | `== !=` | 左到右 |
-| 位与 | `&` | 左到右 |
-| 位异或 | `^` | 左到右 |
-| 位或 | ` | ` | 左到右 |
-| 逻辑与 | `&&` | 左到右 |
-| 逻辑或 | ` | | ` | 左到右 |
-| 条件判断 | `?:` | 右到左 |
-| 赋值 | `= += -= \*= /= %= >>= <<= &= ^= | =` | 右到左 |
-| 逗号 | `,` | 左到右 |
+| **类别** | **操作符** | **结合性** |
+| --------- | ------------------------------------- | ---------- |
+| 后缀 | `() [] .` (点运算符) | 左到右 |
+| 一元 | `++ - - ! ~` | 右到左 |
+| 可乘性 | `* / %` | 左到右 |
+| 可加性 | `+ -` | 左到右 |
+| 移位 | `>> >>> <<` | 左到右 |
+| 关系 | `> >= < <=` | 左到右 |
+| 相等/不等 | `== !=` | 左到右 |
+| 位与 | `&` | 左到右 |
+| 位异或 | `^` | 左到右 |
+| 位或 | `|` | 左到右 |
+| 逻辑与 | `&&` | 左到右 |
+| 逻辑或 | `| |` | 左到右 |
+| 条件判断 | `?:` | 右到左 |
+| 赋值 | `= += -= \*= /= %= >>= <<= &= ^= | =` | 右到左 |
+| 逗号 | `,` | 左到右 |
### JSP 字面量
@@ -1354,7 +1354,7 @@ Apache Tomcat 安装 JSTL 库步骤如下:
```
-使用任何库,你必须在每个 JSP 文件中的头部包含 **** 标签。
+使用任何库,你必须在每个 JSP 文件中的头部包含 **``** 标签。
### 核心标签
@@ -1364,22 +1364,22 @@ Apache Tomcat 安装 JSTL 库步骤如下:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
```
-| 标签 | 描述 |
-| :---------------------------------------------------------------------- | :-------------------------------------------------------------------------- |
-| [``](http://www.runoob.com/jsp/jstl-core-out-tag.html) | 用于在 JSP 中显示数据,就像<%= ... > |
-| [``](http://www.runoob.com/jsp/jstl-core-set-tag.html) | 用于保存数据 |
-| [``](http://www.runoob.com/jsp/jstl-core-remove-tag.html) | 用于删除数据 |
-| [``](http://www.runoob.com/jsp/jstl-core-catch-tag.html) | 用来处理产生错误的异常状况,并且将错误信息储存起来 |
-| [``](http://www.runoob.com/jsp/jstl-core-if-tag.html) | 与我们在一般程序中用的 if 一样 |
-| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | 本身只当做和的父标签 |
-| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | 的子标签,用来判断条件是否成立 |
-| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | 的子标签,接在标签后,当标签判断为 false 时被执行 |
-| [``](http://www.runoob.com/jsp/jstl-core-import-tag.html) | 检索一个绝对或相对 URL,然后将其内容暴露给页面 |
-| [``](http://www.runoob.com/jsp/jstl-core-foreach-tag.html) | 基础迭代标签,接受多种集合类型 |
-| [``](http://www.runoob.com/jsp/jstl-core-foreach-tag.html) | 根据指定的分隔符来分隔内容并迭代输出 |
-| [``](http://www.runoob.com/jsp/jstl-core-param-tag.html) | 用来给包含或重定向的页面传递参数 |
-| [``](http://www.runoob.com/jsp/jstl-core-redirect-tag.html) | 重定向至一个新的 URL. |
-| [``](http://www.runoob.com/jsp/jstl-core-url-tag.html) | 使用可选的查询参数来创造一个 URL |
+| 标签 | 描述 |
+| :---------------------------------------------------------------------- |:------------------------------------------------------------------|
+| [``](http://www.runoob.com/jsp/jstl-core-out-tag.html) | 用于在 JSP 中显示数据,就像<%= ... > |
+| [``](http://www.runoob.com/jsp/jstl-core-set-tag.html) | 用于保存数据 |
+| [``](http://www.runoob.com/jsp/jstl-core-remove-tag.html) | 用于删除数据 |
+| [``](http://www.runoob.com/jsp/jstl-core-catch-tag.html) | 用来处理产生错误的异常状况,并且将错误信息储存起来 |
+| [``](http://www.runoob.com/jsp/jstl-core-if-tag.html) | 与我们在一般程序中用的 if 一样 |
+| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | 本身只当做 `` 和 `` 的父标签 |
+| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | `` 的子标签,用来判断条件是否成立 |
+| [``](http://www.runoob.com/jsp/jstl-core-choose-tag.html) | `` 的子标签,接在 `` 标签后,当 `` 标签判断为 false 时被执行 |
+| [``](http://www.runoob.com/jsp/jstl-core-import-tag.html) | 检索一个绝对或相对 URL,然后将其内容暴露给页面 |
+| [``](http://www.runoob.com/jsp/jstl-core-foreach-tag.html) | 基础迭代标签,接受多种集合类型 |
+| [``](http://www.runoob.com/jsp/jstl-core-foreach-tag.html) | 根据指定的分隔符来分隔内容并迭代输出 |
+| [``](http://www.runoob.com/jsp/jstl-core-param-tag.html) | 用来给包含或重定向的页面传递参数 |
+| [``](http://www.runoob.com/jsp/jstl-core-redirect-tag.html) | 重定向至一个新的 URL. |
+| [``](http://www.runoob.com/jsp/jstl-core-url-tag.html) | 使用可选的查询参数来创造一个 URL |
### 格式化标签
@@ -1438,18 +1438,18 @@ JSTL XML 标签库提供了创建和操作 XML 文档的标签。引用 XML 标
下载地址:
-| 标签 | 描述 |
-| :----------------------------------------------------------------------- | :---------------------------------------------------------- |
-| [``](http://www.runoob.com/jsp/jstl-xml-out-tag.html) | 与<%= ... >,类似,不过只用于 XPath 表达式 |
-| [``](http://www.runoob.com/jsp/jstl-xml-parse-tag.html) | 解析 XML 数据 |
-| [``](http://www.runoob.com/jsp/jstl-xml-set-tag.html) | 设置 XPath 表达式 |
-| [``](http://www.runoob.com/jsp/jstl-xml-if-tag.html) | 判断 XPath 表达式,若为真,则执行本体中的内容,否则跳过本体 |
-| [``](http://www.runoob.com/jsp/jstl-xml-foreach-tag.html) | 迭代 XML 文档中的节点 |
-| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | 和的父标签 |
-| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | 的子标签,用来进行条件判断 |
-| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | 的子标签,当判断为 false 时被执行 |
-| [``](http://www.runoob.com/jsp/jstl-xml-transform-tag.html) | 将 XSL 转换应用在 XML 文档中 |
-| [``](http://www.runoob.com/jsp/jstl-xml-param-tag.html) | 与共同使用,用于设置 XSL 样式表 |
+| 标签 | 描述 |
+| :----------------------------------------------------------------------- |:----------------------------------------------|
+| [``](http://www.runoob.com/jsp/jstl-xml-out-tag.html) | 与 `<%= ... >`,类似,不过只用于 XPath 表达式 |
+| [``](http://www.runoob.com/jsp/jstl-xml-parse-tag.html) | 解析 XML 数据 |
+| [``](http://www.runoob.com/jsp/jstl-xml-set-tag.html) | 设置 XPath 表达式 |
+| [``](http://www.runoob.com/jsp/jstl-xml-if-tag.html) | 判断 XPath 表达式,若为真,则执行本体中的内容,否则跳过本体 |
+| [``](http://www.runoob.com/jsp/jstl-xml-foreach-tag.html) | 迭代 XML 文档中的节点 |
+| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | `` 和 `` 的父标签 |
+| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | `` 的子标签,用来进行条件判断 |
+| [``](http://www.runoob.com/jsp/jstl-xml-choose-tag.html) | `` 的子标签,当 `` 判断为 false 时被执行 |
+| [``](http://www.runoob.com/jsp/jstl-xml-transform-tag.html) | 将 XSL 转换应用在 XML 文档中 |
+| [``](http://www.runoob.com/jsp/jstl-xml-param-tag.html) | 与 `` 共同使用,用于设置 XSL 样式表 |
### JSTL 函数
@@ -1650,7 +1650,7 @@ public class HelloTag extends SimpleTagSupport {
}
```
-属性的名称是"message",所以 setter 方法是的 setMessage()。现在让我们在 TLD 文件中使用的元素添加此属性:
+属性的名称是"message",所以 setter 方法是的 setMessage()。现在让我们在 TLD 文件中使用的 `` 元素添加此属性:
```
@@ -1728,4 +1728,4 @@ This is custom tag
java.util.Date
.....
-```
+```
\ No newline at end of file
diff --git "a/docs/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md" "b/docs/01.Java/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md"
similarity index 98%
rename from "docs/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md"
rename to "docs/01.Java/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md"
index f13e99be..aea60247 100644
--- "a/docs/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md"
+++ "b/docs/01.Java/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md"
@@ -1,17 +1,17 @@
---
title: JavaWeb 之 Filter 和 Listener
-categories:
- - 编程
+date: 2020-08-24 19:41:46
+order: 03
+categories:
- Java
+ - JavaEE
- JavaWeb
-tags:
+tags:
- Java
- JavaWeb
- Filter
- Listener
-abbrlink: 9eb5517a
-date: 2020-08-24 19:41:46
-permalink: /pages/5ecb29/
+permalink: /pages/82df5f/
---
# JavaWeb 之 Filter 和 Listener
@@ -24,7 +24,7 @@ permalink: /pages/5ecb29/
Filter 提供了过滤链(Filter Chain)的概念,一个过滤链包括多个 Filter。客户端请求 request 在抵达 Servlet 之前会经过过滤链的所有 Filter,服务器响应 response 从 Servlet 抵达客户端浏览器之前也会经过过滤链的所有 FIlter。
-
+
### 过滤器方法
@@ -215,4 +215,4 @@ Filter 和 Listener 的本质区别:
## 参考资料
- [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
-- [Java Web 整合开发王者归来](https://book.douban.com/subject/4189495/)
+- [Java Web 整合开发王者归来](https://book.douban.com/subject/4189495/)
\ No newline at end of file
diff --git "a/docs/02.JavaEE/01.JavaWeb/04.JavaWeb\344\271\213Cookie\345\222\214Session.md" "b/docs/01.Java/02.JavaEE/01.JavaWeb/04.JavaWeb\344\271\213Cookie\345\222\214Session.md"
similarity index 99%
rename from "docs/02.JavaEE/01.JavaWeb/04.JavaWeb\344\271\213Cookie\345\222\214Session.md"
rename to "docs/01.Java/02.JavaEE/01.JavaWeb/04.JavaWeb\344\271\213Cookie\345\222\214Session.md"
index 9358744c..3729f4a6 100644
--- "a/docs/02.JavaEE/01.JavaWeb/04.JavaWeb\344\271\213Cookie\345\222\214Session.md"
+++ "b/docs/01.Java/02.JavaEE/01.JavaWeb/04.JavaWeb\344\271\213Cookie\345\222\214Session.md"
@@ -1,17 +1,17 @@
---
title: JavaWeb 之 Cookie 和 Session
-categories:
- - 编程
+date: 2020-08-24 19:41:46
+order: 04
+categories:
- Java
+ - JavaEE
- JavaWeb
-tags:
+tags:
- Java
- JavaWeb
- Cookie
- Session
-abbrlink: bb93a37b
-date: 2020-08-24 19:41:46
-permalink: /pages/e61883/
+permalink: /pages/c46bff/
---
# JavaWeb 之 Cookie 和 Session
@@ -587,4 +587,4 @@ Cookie 需要浏览器支持才能使用。
### 跨域名
- Cookie 支持跨域名。
-- Session 不支持跨域名。
+- Session 不支持跨域名。
\ No newline at end of file
diff --git "a/docs/02.JavaEE/01.JavaWeb/99.JavaWeb\351\235\242\347\273\217.md" "b/docs/01.Java/02.JavaEE/01.JavaWeb/99.JavaWeb\351\235\242\347\273\217.md"
similarity index 99%
rename from "docs/02.JavaEE/01.JavaWeb/99.JavaWeb\351\235\242\347\273\217.md"
rename to "docs/01.Java/02.JavaEE/01.JavaWeb/99.JavaWeb\351\235\242\347\273\217.md"
index e5a71bb9..8e803b40 100644
--- "a/docs/02.JavaEE/01.JavaWeb/99.JavaWeb\351\235\242\347\273\217.md"
+++ "b/docs/01.Java/02.JavaEE/01.JavaWeb/99.JavaWeb\351\235\242\347\273\217.md"
@@ -1,16 +1,16 @@
---
title: JavaWeb 面经
-categories:
- - 编程
+date: 2020-02-07 23:04:47
+order: 99
+categories:
- Java
+ - JavaEE
- JavaWeb
-tags:
+tags:
- Java
- JavaWeb
- Servlet
-abbrlink: f216aa98
-date: 2020-02-07 23:04:47
-permalink: /pages/1933b3/
+permalink: /pages/e175ce/
---
# JavaWeb 面经
@@ -266,4 +266,4 @@ Servlet 生命周期如下:
## 参考资料
- https://blog.csdn.net/YM_IlY/article/details/81266959
-- https://www.jianshu.com/p/f073dde56262
+- https://www.jianshu.com/p/f073dde56262
\ No newline at end of file
diff --git a/docs/02.JavaEE/01.JavaWeb/README.md b/docs/01.Java/02.JavaEE/01.JavaWeb/README.md
similarity index 86%
rename from docs/02.JavaEE/01.JavaWeb/README.md
rename to docs/01.Java/02.JavaEE/01.JavaWeb/README.md
index 5f07df05..56a9b42a 100644
--- a/docs/02.JavaEE/01.JavaWeb/README.md
+++ b/docs/01.Java/02.JavaEE/01.JavaWeb/README.md
@@ -1,15 +1,15 @@
---
title: JavaWeb
-categories:
- - 编程
+date: 2020-02-07 23:04:47
+categories:
- Java
+ - JavaEE
- JavaWeb
-tags:
+tags:
- JavaWeb
+permalink: /pages/50f49f/
hidden: true
-abbrlink: 99720b1c
-date: 2020-02-07 23:04:47
-permalink: /pages/c1cee9/
+index: false
---
# ☕ JavaWeb
@@ -31,4 +31,4 @@ permalink: /pages/c1cee9/
- [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
- [Servlet 教程](https://www.runoob.com/servlet/servlet-tutorial.html)
- [博客园孤傲苍狼 JavaWeb 学习总结](https://www.cnblogs.com/xdp-gacl/tag/JavaWeb%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/)
- - [JSP 教程](https://www.runoob.com/jsp/jsp-tutorial.html)
+ - [JSP 教程](https://www.runoob.com/jsp/jsp-tutorial.html)
\ No newline at end of file
diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md"
similarity index 95%
rename from "docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md"
index 77264e08..05822b5e 100644
--- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md"
@@ -1,17 +1,18 @@
---
title: Tomcat 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 01
+categories:
- Java
+ - JavaEE
- 服务器
-tags:
+ - Tomcat
+tags:
- Java
- JavaWeb
- 服务器
- Tomcat
-abbrlink: ea4ca089
-date: 2022-02-17 22:34:30
-permalink: /pages/c50d2b/
+permalink: /pages/4a4c02/
---
# Tomcat 快速入门
@@ -111,7 +112,7 @@ tar -zxf apache-tomcat-8.5.24.tar.gz
启动后,访问 `http://localhost:8080` ,可以看到 Tomcat 安装成功的测试页面。
-
+
### 2.2. 配置
@@ -364,7 +365,7 @@ public class SimpleTomcatServer {
- 设置启动应用的端口、JVM 参数、启动浏览器等。
- 成功后,可以访问 `http://localhost:8080/`(当然,你也可以在 url 中设置上下文名称)。
-
+
> **说明**
>
@@ -374,7 +375,7 @@ public class SimpleTomcatServer {
## 3. Tomcat 架构
-
+
Tomcat 要实现 2 个核心功能:
@@ -402,7 +403,7 @@ Tomcat 支持的应用层协议有:
Tomcat 支持多种 I/O 模型和应用层协议。为了实现这点,一个容器可能对接多个连接器。但是,单独的连接器或容器都不能对外提供服务,需要把它们组装起来才能工作,组装后这个整体叫作 Service 组件。Tomcat 内可能有多个 Service,通过在 Tomcat 中配置多个 Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用。
-
+
**一个 Tomcat 实例有一个或多个 Service;一个 Service 有多个 Connector 和 Container**。Connector 和 Container 之间通过标准的 ServletRequest 和 ServletResponse 通信。
@@ -418,13 +419,13 @@ Tomcat 支持多种 I/O 模型和应用层协议。为了实现这点,一个
Tomcat 设计了 3 个组件来实现这 3 个功能,分别是 **`EndPoint`**、**`Processor`** 和 **`Adapter`**。
-
+
组件间通过抽象接口交互。这样做还有一个好处是**封装变化。**这是面向对象设计的精髓,将系统中经常变化的部分和稳定的部分隔离,有助于增加复用性,并降低系统耦合度。网络通信的 I/O 模型是变化的,可能是非阻塞 I/O、异步 I/O 或者 APR。应用层协议也是变化的,可能是 HTTP、HTTPS、AJP。浏览器端发送的请求信息也是变化的。但是整体的处理逻辑是不变的,EndPoint 负责提供字节流给 Processor,Processor 负责提供 Tomcat Request 对象给 Adapter,Adapter 负责提供 ServletRequest 对象给容器。
如果要支持新的 I/O 方案、新的应用层协议,只需要实现相关的具体子类,上层通用的处理逻辑是不变的。由于 I/O 模型和应用层协议可以自由组合,比如 NIO + HTTP 或者 NIO2 + AJP。Tomcat 的设计者将网络通信和应用层协议解析放在一起考虑,设计了一个叫 ProtocolHandler 的接口来封装这两种变化点。各种协议和通信模型的组合有相应的具体实现类。比如:Http11NioProtocol 和 AjpNioProtocol。
-
+
#### 3.2.1. ProtocolHandler 组件
@@ -444,7 +445,7 @@ EndPoint 是一个接口,对应的抽象实现类是 AbstractEndpoint,而 Ab
Processor 是一个接口,定义了请求的处理等方法。它的抽象实现类 AbstractProcessor 对一些协议共有的属性进行封装,没有对方法进行实现。具体的实现有 AJPProcessor、HTTP11Processor 等,这些具体实现类实现了特定协议的解析方法和请求处理方式。
-
+
从图中我们看到,EndPoint 接收到 Socket 连接后,生成一个 SocketProcessor 任务提交到线程池去处理,SocketProcessor 的 Run 方法会调用 Processor 组件去解析应用层协议,Processor 通过解析生成 Request 对象后,会调用 Adapter 的 Service 方法。
@@ -471,7 +472,7 @@ Tomcat 是怎么确定请求是由哪个 Wrapper 容器里的 Servlet 来处理
举例来说,假如有一个网购系统,有面向网站管理人员的后台管理系统,还有面向终端客户的在线购物系统。这两个系统跑在同一个 Tomcat 上,为了隔离它们的访问域名,配置了两个虚拟域名:`manage.shopping.com`和`user.shopping.com`,网站管理人员通过`manage.shopping.com`域名访问 Tomcat 去管理用户和商品,而用户管理和商品管理是两个单独的 Web 应用。终端客户通过`user.shopping.com`域名去搜索商品和下订单,搜索功能和订单管理也是两个独立的 Web 应用。如下所示,演示了 url 应声 Servlet 的处理流程。
-
+
假如有用户访问一个 URL,比如图中的`http://user.shopping.com:8080/order/buy`,Tomcat 如何将这个 URL 定位到一个 Servlet 呢?
@@ -490,7 +491,7 @@ Pipeline-Valve 是责任链模式,责任链模式是指在一个请求处理
先来了解一下 Valve 和 Pipeline 接口的设计:
-
+
- 每一个容器都有一个 Pipeline 对象,只要触发这个 Pipeline 的第一个 Valve,这个容器里 Pipeline 中的 Valve 就都会被调用到。但是,不同容器的 Pipeline 是怎么链式触发的呢,比如 Engine 中 Pipeline 需要调用下层容器 Host 中的 Pipeline。
- 这是因为 Pipeline 中还有个 getBasic 方法。这个 BasicValve 处于 Valve 链表的末端,它是 Pipeline 中必不可少的一个 Valve,负责调用下层容器的 Pipeline 里的第一个 Valve。
@@ -499,7 +500,7 @@ Pipeline-Valve 是责任链模式,责任链模式是指在一个请求处理
- 各层容器对应的 basic valve 分别是 `StandardEngineValve`、`StandardHostValve`、 `StandardContextValve`、`StandardWrapperValve`。
- 由于 Valve 是一个处理点,因此 invoke 方法就是来处理请求的。注意到 Valve 中有 getNext 和 setNext 方法,因此我们大概可以猜到有一个链表将 Valve 链起来了。
-
+
整个调用过程由连接器中的 Adapter 触发的,它会调用 Engine 的第一个 Valve:
@@ -511,7 +512,7 @@ connector.getService().getContainer().getPipeline().getFirst().invoke(request, r
### 4.1. Tomcat 的启动过程
-
+
1. Tomcat 是一个 Java 程序,它的运行从执行 `startup.sh` 脚本开始。`startup.sh` 会启动一个 JVM 来运行 Tomcat 的启动类 `Bootstrap`。
2. `Bootstrap` 会初始化 Tomcat 的类加载器并实例化 `Catalina`。
@@ -731,12 +732,12 @@ ContextConfig 解析 web.xml 顺序:
### 4.3. LifeCycle
-
+
#### 4.3.1. 请求处理过程
-

+
1. 根据 server.xml 配置的指定的 connector 以及端口监听 http、或者 ajp 请求
@@ -747,25 +748,25 @@ ContextConfig 解析 web.xml 顺序:
### 4.4. Connector 流程
-

+
#### 4.4.1. 阻塞 IO
-

+
#### 4.4.2. 非阻塞 IO
-

+
#### 4.4.3. IO 多路复用
-

+
阻塞与非阻塞的区别在于进行读操作和写操作的系统调用时,如果此时内核态没有数据可读或者没有缓冲空间可写时,是否阻塞。
@@ -775,7 +776,7 @@ IO 多路复用的好处在于可同时监听多个 socket 的可读和可写事
#### 4.4.4. Tomcat 各类 Connector 对比
-

+
- JIO:用 java.io 编写的 TCP 模块,阻塞 IO
@@ -796,7 +797,7 @@ Apache Portable Runtime 是一个高度可移植的库,它是 Apache HTTP Serv
**NIO 处理相关类**
-

+
Poller 线程从 EventQueue 获取 PollerEvent,并执行 PollerEvent 的 run 方法,调用 Selector 的 select 方法,如果有可读的 Socket 则创建 Http11NioProcessor,放入到线程池中执行;
@@ -829,7 +830,7 @@ Note:
### 4.6. 异步 Servlet
-

+
传统流程:
@@ -839,7 +840,7 @@ Note:
- 最后,根据处理的结果提交响应,Servlet 线程结束
-

+
异步处理流程:
@@ -882,4 +883,4 @@ onComplete 执行后,就不可再操作 request 和 response
- [Creating a Web App with Bootstrap and Tomcat Embedded](http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/basic_app_embedded_tomcat/basic_app-tomcat-embedded.html)
- [Tomcat 组成与工作原理](https://juejin.im/post/58eb5fdda0bb9f00692a78fc)
- [Tomcat 工作原理](https://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/index.html)
- - [Tomcat 设计模式分析](https://www.ibm.com/developerworks/cn/java/j-lo-tomcat2/index.html?ca=drs-)
+ - [Tomcat 设计模式分析](https://www.ibm.com/developerworks/cn/java/j-lo-tomcat2/index.html?ca=drs-)
\ No newline at end of file
diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md"
similarity index 98%
rename from "docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md"
index d76dc06d..fbf9fe8e 100644
--- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md"
@@ -1,17 +1,18 @@
---
title: Tomcat连接器
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 02
+categories:
- Java
+ - JavaEE
- 服务器
-tags:
+ - Tomcat
+tags:
- Java
- JavaWeb
- 服务器
- Tomcat
-abbrlink: 23822cab
-date: 2022-02-17 22:34:30
-permalink: /pages/3c954b/
+permalink: /pages/13f070/
---
# Tomcat 连接器
@@ -20,7 +21,7 @@ permalink: /pages/3c954b/
Tomcat 的 NioEndPoint 组件利用 Java NIO 实现了 I/O 多路复用模型。
-
+
NioEndPoint 子组件功能简介:
@@ -123,7 +124,7 @@ private final SynchronizedQueue events = new SynchronizedQueue<>();
Nio2Endpoint 工作流程跟 NioEndpoint 较为相似。
-
+
Nio2Endpoint 子组件功能说明:
@@ -218,7 +219,7 @@ Tomcat 本身是 Java 编写的,为了调用 C 语言编写的 APR,需要通
### 3.1. AprEndpoint 工作流程
-
+
#### 3.1.1. Acceptor
@@ -282,7 +283,7 @@ java my.class
这个命令行中的`java`其实是**一个可执行程序,这个程序会创建 JVM 来加载和运行你的 Java 类**。操作系统会创建一个进程来执行这个`java`可执行程序,而每个进程都有自己的虚拟地址空间,JVM 用到的内存(包括堆、栈和方法区)就是从进程的虚拟地址空间上分配的。请你注意的是,JVM 内存只是进程空间的一部分,除此之外进程空间内还有代码段、数据段、内存映射区、内核空间等。从 JVM 的角度看,JVM 内存之外的部分叫作本地内存,C 程序代码在运行过程中用到的内存就是本地内存中分配的。下面我们通过一张图来理解一下。
-
+
Tomcat 的 Endpoint 组件在接收网络数据时需要预先分配好一块 Buffer,所谓的 Buffer 就是字节数组`byte[]`,Java 通过 JNI 调用把这块 Buffer 的地址传给 C 代码,C 代码通过操作系统 API 读取 Socket 并把数据填充到这块 Buffer。Java NIO API 提供了两种 Buffer 来接收数据:HeapByteBuffer 和 DirectByteBuffer,下面的代码演示了如何创建两种 Buffer。
@@ -323,7 +324,7 @@ Tomcat 中的 AprEndpoint 就是通过 DirectByteBuffer 来接收数据的,而
从下面的图你会发现这个过程有 6 次内存拷贝,并且 read 和 write 等系统调用将导致进程从用户态到内核态的切换,会耗费大量的 CPU 和内存资源。
-
+
而 Tomcat 的 AprEndpoint 通过操作系统层面的 sendfile 特性解决了这个问题,sendfile 系统调用方式非常简洁。
@@ -337,7 +338,7 @@ sendfile(socket, file, len);
第二步:数据并没有从内核缓冲区复制到 Socket 关联的缓冲区,只有记录数据位置和长度的描述符被添加到 Socket 缓冲区中;接着把数据直接从内核缓冲区传递给网卡。这个过程你可以看下面的图。
-
+
## 4. Executor 组件
@@ -508,7 +509,7 @@ Tomcat 用 ProtocolHandler 组件屏蔽应用层协议的差异,其中 Protoco
WebSocket 是通过 HTTP 协议来进行握手的,因此当 WebSocket 的握手请求到来时,HttpProtocolHandler 首先接收到这个请求,在处理这个 HTTP 请求时,Tomcat 通过一个特殊的 Filter 判断该当前 HTTP 请求是否是一个 WebSocket Upgrade 请求(即包含`Upgrade: websocket`的 HTTP 头信息),如果是,则在 HTTP 响应里添加 WebSocket 相关的响应头信息,并进行协议升级。具体来说就是用 UpgradeProtocolHandler 替换当前的 HttpProtocolHandler,相应的,把当前 Socket 的 Processor 替换成 UpgradeProcessor,同时 Tomcat 会创建 WebSocket Session 实例和 Endpoint 实例,并跟当前的 WebSocket 连接一一对应起来。这个 WebSocket 连接不会立即关闭,并且在请求处理中,不再使用原有的 HttpProcessor,而是用专门的 UpgradeProcessor,UpgradeProcessor 最终会调用相应的 Endpoint 实例来处理请求。
-
+
你可以看到,Tomcat 对 WebSocket 请求的处理没有经过 Servlet 容器,而是通过 UpgradeProcessor 组件直接把请求发到 ServerEndpoint 实例,并且 Tomcat 的 WebSocket 实现不需要关注具体 I/O 模型的细节,从而实现了与具体 I/O 方式的解耦。
@@ -519,4 +520,4 @@ WebSocket 是通过 HTTP 协议来进行握手的,因此当 WebSocket 的握
- [Tomcat Wiki](http://wiki.apache.org/tomcat/FrontPage)
- [Tomee 官方网站](http://tomee.apache.org/)
- **教程**
- - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+ - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
\ No newline at end of file
diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md"
similarity index 99%
rename from "docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md"
index d72a1c6b..0f71d9ce 100644
--- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md"
@@ -1,17 +1,18 @@
---
title: Tomcat容器
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 03
+categories:
- Java
+ - JavaEE
- 服务器
-tags:
+ - Tomcat
+tags:
- Java
- JavaWeb
- 服务器
- Tomcat
-abbrlink: fc56014a
-date: 2022-02-17 22:34:30
-permalink: /pages/2fea08/
+permalink: /pages/d5076a/
---
# Tomcat 容器
@@ -335,7 +336,7 @@ Tomcat 作为 Web 容器,需要解决以下问题:
2. 两个 Web 应用都依赖同一个第三方的 JAR 包,比如 Spring,那 Spring 的 JAR 包被加载到内存后,Tomcat 要保证这两个 Web 应用能够共享,也就是说 Spring 的 JAR 包只被加载一次,否则随着依赖的第三方 JAR 包增多,JVM 的内存会膨胀。
3. 需要隔离 Tomcat 本身的类和 Web 应用的类。
-
+
#### WebAppClassLoader
@@ -724,4 +725,4 @@ public boolean processSocket(SocketWrapperBase socketWrapper,
- [Tomcat Wiki](http://wiki.apache.org/tomcat/FrontPage)
- [Tomee 官方网站](http://tomee.apache.org/)
- **教程**
- - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+ - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
\ No newline at end of file
diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/04.Tomcat\344\274\230\345\214\226.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/04.Tomcat\344\274\230\345\214\226.md"
similarity index 98%
rename from "docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/04.Tomcat\344\274\230\345\214\226.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/04.Tomcat\344\274\230\345\214\226.md"
index 67cefb7e..3beb96e8 100644
--- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/04.Tomcat\344\274\230\345\214\226.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/04.Tomcat\344\274\230\345\214\226.md"
@@ -1,17 +1,18 @@
---
title: Tomcat优化
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 04
+categories:
- Java
+ - JavaEE
- 服务器
-tags:
+ - Tomcat
+tags:
- Java
- JavaWeb
- 服务器
- Tomcat
-abbrlink: c37025e9
-date: 2022-02-17 22:34:30
-permalink: /pages/6c22f4/
+permalink: /pages/f9e1e6/
---
# Tomcat 优化
@@ -152,4 +153,4 @@ Tomcat 启动的时候,默认情况下 Web 应用都是一个一个启动的
- [Tomcat Wiki](http://wiki.apache.org/tomcat/FrontPage)
- [Tomee 官方网站](http://tomee.apache.org/)
- **教程**
- - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
+ - [深入拆解 Tomcat & Jetty](https://time.geekbang.org/column/intro/100027701)
\ No newline at end of file
diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/05.Tomcat\345\222\214Jetty.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/05.Tomcat\345\222\214Jetty.md"
similarity index 95%
rename from "docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/05.Tomcat\345\222\214Jetty.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/05.Tomcat\345\222\214Jetty.md"
index 3bb92e84..a841530f 100644
--- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/05.Tomcat\345\222\214Jetty.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/05.Tomcat\345\222\214Jetty.md"
@@ -1,18 +1,19 @@
---
title: Tomcat 和 Jetty
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 05
+categories:
- Java
+ - JavaEE
- 服务器
-tags:
+ - Tomcat
+tags:
- Java
- JavaWeb
- 服务器
- Tomcat
- Jetty
-abbrlink: a6fd024b
-date: 2022-02-17 22:34:30
-permalink: /pages/f1bba6/
+permalink: /pages/f37326/
---
## Tomcat 和 Jetty
@@ -31,4 +32,4 @@ Web 容器 Tomcat 或 Jetty,作为重要的系统中间件,连接着浏览
其他应用服务器比如 JBoss 和 WebLogic,它们不仅仅有 Servlet 容器的功能,也包含 EJB 容器,是完整的 Java EE 应用服务器。从这个角度看,Tomcat 和 Jetty 算是一个轻量级的应用服务器。
-在微服务架构日渐流行的今天,开发人员更喜欢稳定的、轻量级的应用服务器,并且应用程序用内嵌的方式来运行 Servlet 容器也逐渐流行起来。之所以选择轻量级,是因为在微服务架构下,我们把一个大而全的单体应用,拆分成一个个功能单一的微服务,在这个过程中,服务的数量必然要增加,但为了减少资源的消耗,并且降低部署的成本,我们希望运行服务的 Web 容器也是轻量级的,Web 容器本身应该消耗较少的内存和 CPU 资源,并且由应用本身来启动一个嵌入式的 Web 容器,而不是通过 Web 容器来部署和启动应用,这样可以降低应用部署的复杂度。
+在微服务架构日渐流行的今天,开发人员更喜欢稳定的、轻量级的应用服务器,并且应用程序用内嵌的方式来运行 Servlet 容器也逐渐流行起来。之所以选择轻量级,是因为在微服务架构下,我们把一个大而全的单体应用,拆分成一个个功能单一的微服务,在这个过程中,服务的数量必然要增加,但为了减少资源的消耗,并且降低部署的成本,我们希望运行服务的 Web 容器也是轻量级的,Web 容器本身应该消耗较少的内存和 CPU 资源,并且由应用本身来启动一个嵌入式的 Web 容器,而不是通过 Web 容器来部署和启动应用,这样可以降低应用部署的复杂度。
\ No newline at end of file
diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/README.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/README.md"
similarity index 72%
rename from "docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/README.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/README.md"
index a7fc606a..6204b0c8 100644
--- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/README.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/README.md"
@@ -1,18 +1,19 @@
---
title: Tomcat 教程
-categories:
- - 编程
+date: 2022-02-18 08:53:11
+categories:
- Java
+ - JavaEE
- 服务器
-tags:
+ - Tomcat
+tags:
- Java
- JavaWeb
- 服务器
- Tomcat
+permalink: /pages/33e817/
hidden: true
-abbrlink: 3804ebfc
-date: 2022-02-18 08:53:11
-permalink: /pages/86288e/
+index: false
---
# Tomcat 教程
@@ -32,4 +33,4 @@ permalink: /pages/86288e/
## 🚪 传送
-◾ 🏠 [JAVA-TUTORIAL 首页](https://github.com/dunwu/java-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md"
similarity index 99%
rename from "docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md"
index 369b7409..db02b55c 100644
--- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md"
@@ -1,17 +1,17 @@
---
title: Jetty 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 02
+categories:
- Java
+ - JavaEE
- 服务器
-tags:
+tags:
- Java
- JavaWeb
- 服务器
- Jetty
-abbrlink: 9709eee9
-date: 2022-02-17 22:34:30
-permalink: /pages/9ecdc1/
+permalink: /pages/ec364e/
---
# Jetty 快速入门
@@ -254,7 +254,7 @@ mvn jetty:run
### Jetty 架构简介
-
+
Jetty Server 就是由多个 Connector(连接器)、多个 Handler(处理器),以及一个线程池组成。
@@ -379,7 +379,7 @@ getEndPoint().fillInterested(_readCallback);
到此你应该了解了 Connector 的工作原理,下面我画张图再来回顾一下 Connector 的工作流程。
-
+
1. Acceptor 监听连接请求,当有连接请求到达时就接受连接,一个连接对应一个 Channel,Acceptor 将 Channel 交给 ManagedSelector 来处理。
@@ -427,7 +427,7 @@ public interface Handler extends LifeCycle, Destroyable
Handler 只是一个接口,完成具体功能的还是它的子类。那么 Handler 有哪些子类呢?它们的继承关系又是怎样的?这些子类是如何实现 Servlet 容器功能的呢?
-
+
在 AbstractHandler 之下有 AbstractHandlerContainer,为什么需要这个类呢?这其实是个过渡,为了实现链式调用,一个 Handler 内部必然要有其他 Handler 的引用,所以这个类的名字里才有 Container,意思就是这样的 Handler 里包含了其他 Handler 的引用。
@@ -674,4 +674,4 @@ SelectorProducer 是 ManagedSelector 的内部类,SelectorProducer 实现了 E
- [Jetty 官方网址](http://www.eclipse.org/jetty/index.html)
- [Jetty Github](https://github.com/eclipse/jetty.project)
-- [Jetty wiki](http://wiki.eclipse.org/Jetty/Reference/jetty-env.xml)
+- [Jetty wiki](http://wiki.eclipse.org/Jetty/Reference/jetty-env.xml)
\ No newline at end of file
diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/README.md" "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/README.md"
similarity index 80%
rename from "docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/README.md"
rename to "docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/README.md"
index 595e3d43..9e9a4473 100644
--- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/README.md"
+++ "b/docs/01.Java/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/README.md"
@@ -1,17 +1,17 @@
---
title: Java 服务器
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+categories:
- Java
+ - JavaEE
- 服务器
-tags:
+tags:
- Java
- JavaWeb
- 服务器
+permalink: /pages/e3f3f3/
hidden: true
-abbrlink: c34dbf07
-date: 2022-02-17 22:34:30
-permalink: /pages/9d17ce/
+index: false
---
# Java 服务器
@@ -36,4 +36,4 @@ permalink: /pages/9d17ce/
## 🚪 传送
-◾ 🏠 [JAVA-TUTORIAL 首页](https://github.com/dunwu/java-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git a/docs/02.JavaEE/README.md b/docs/01.Java/02.JavaEE/README.md
similarity index 93%
rename from docs/02.JavaEE/README.md
rename to docs/01.Java/02.JavaEE/README.md
index d70da973..846c3677 100644
--- a/docs/02.JavaEE/README.md
+++ b/docs/01.Java/02.JavaEE/README.md
@@ -1,16 +1,15 @@
---
title: JavaEE
-categories:
- - 编程
+date: 2022-02-18 08:53:11
+categories:
- Java
- JavaEE
-tags:
+tags:
- Java
- JavaEE
+permalink: /pages/80a822/
hidden: true
-abbrlink: 37aa865c
-date: 2022-02-18 08:53:11
-permalink: /pages/ca58e7/
+index: false
---
# JavaEE
@@ -59,4 +58,4 @@ permalink: /pages/ca58e7/
## 🚪 传送
-◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾ 🎯 [钝悟的博客](https://dunwu.github.io/blog/) ◾
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md" "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md"
similarity index 96%
rename from "docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md"
index 265088c7..b2efbdda 100644
--- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md"
@@ -1,17 +1,17 @@
---
title: Maven 快速入门
-categories:
- - 编程
+date: 2020-02-07 23:04:47
+order: 01
+categories:
- Java
- 软件
- 构建
-tags:
+ - Maven
+tags:
- Java
- 构建
- Maven
-abbrlink: ad26e4b1
-date: 2020-02-07 23:04:47
-permalink: /pages/6b8149/
+permalink: /pages/e5b79f/
---
# Maven 快速入门
@@ -135,9 +135,9 @@ export PATH=$MAVEN_HOME/bin:$PATH
右键 "计算机",选择 "属性",之后点击 "高级系统设置",点击"环境变量",来设置环境变量,有以下系统变量需要配置:
-
+
-
+
### 检测安装成功
@@ -265,15 +265,15 @@ java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App
依次点击 File -> New -> Project 打开创建工程对话框,选择 Maven 工程。
-
+
(2)输入项目信息
-
+
(3)点击 Intellij 侧边栏中的 Maven 工具界面,有几个可以直接使用的 maven 命令,可以帮助你进行构建。
-
+
### 在 Eclipse 中创建 Maven 工程
@@ -285,7 +285,7 @@ java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App
点击 Help -> Eclipse Marketplace,搜索 maven 关键字,选择安装红框对应的 Maven 插件。
-
+
(2)Maven 环境配置
@@ -293,7 +293,7 @@ java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App
如下图所示,配置 settings.xml 文件的位置
-
+
(3)创建 Maven 工程
@@ -301,7 +301,7 @@ File -> New -> Maven Project -> Next,在接下来的窗口中会看到一大
接下来设置项目的参数,如下:
-
+
**groupId**是项目组织唯一的标识符,实际对应 JAVA 的包的结构,是 main 目录里 java 的目录结构。
@@ -315,11 +315,11 @@ Eclipse 中构建方式:
在 Elipse 项目上右击 -> Run As 就能看到很多 Maven 操作。这些操作和 maven 命令是等效的。例如 Maven clean,等同于 mvn clean 命令。
-
+
你也可以点击 Maven build,输入组合命令,并保存下来。如下图:
-
+
Maven 命令构建方式:
@@ -327,7 +327,7 @@ Maven 命令构建方式:
进入工程所在目录,输入 maven 命令就可以了。
-
+
## 使用说明
@@ -554,4 +554,4 @@ mvn clean install -Dmaven.test.skip=true -B -U
- [Maven in 5 Minutes](https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html)
- [Maven Getting Started Guide](https://maven.apache.org/guides/getting-started/index.html)
- [maven 常见问题问答](http://www.oschina.net/question/158170_29368)
-- [常用 Maven 插件介绍](https://www.cnblogs.com/crazy-fox/archive/2012/02/09/2343722.html)
+- [常用 Maven 插件介绍](https://www.cnblogs.com/crazy-fox/archive/2012/02/09/2343722.html)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/02.Maven\346\225\231\347\250\213\344\271\213pom.xml\350\257\246\350\247\243.md" "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/02.Maven\346\225\231\347\250\213\344\271\213pom.xml\350\257\246\350\247\243.md"
similarity index 99%
rename from "docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/02.Maven\346\225\231\347\250\213\344\271\213pom.xml\350\257\246\350\247\243.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/02.Maven\346\225\231\347\250\213\344\271\213pom.xml\350\257\246\350\247\243.md"
index 60c8a837..d19300f4 100644
--- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/02.Maven\346\225\231\347\250\213\344\271\213pom.xml\350\257\246\350\247\243.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/02.Maven\346\225\231\347\250\213\344\271\213pom.xml\350\257\246\350\247\243.md"
@@ -1,17 +1,17 @@
---
title: Maven 教程之 pom.xml 详解
-categories:
- - 编程
+date: 2019-05-14 14:57:33
+order: 02
+categories:
- Java
- 软件
- 构建
-tags:
+ - Maven
+tags:
- Java
- 构建
- Maven
-abbrlink: 15944f49
-date: 2019-05-14 14:57:33
-permalink: /pages/f594fa/
+permalink: /pages/d893c2/
---
# Maven 教程之 pom.xml 详解
@@ -799,4 +799,4 @@ POM 执行的预设条件。
## 参考资料
-- [maven 官方文档之 pom](https://maven.apache.org/pom.html)
+- [maven 官方文档之 pom](https://maven.apache.org/pom.html)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/03.Maven\346\225\231\347\250\213\344\271\213settings.xml\350\257\246\350\247\243.md" "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/03.Maven\346\225\231\347\250\213\344\271\213settings.xml\350\257\246\350\247\243.md"
similarity index 99%
rename from "docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/03.Maven\346\225\231\347\250\213\344\271\213settings.xml\350\257\246\350\247\243.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/03.Maven\346\225\231\347\250\213\344\271\213settings.xml\350\257\246\350\247\243.md"
index 09f242d8..9fce2931 100644
--- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/03.Maven\346\225\231\347\250\213\344\271\213settings.xml\350\257\246\350\247\243.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/03.Maven\346\225\231\347\250\213\344\271\213settings.xml\350\257\246\350\247\243.md"
@@ -1,17 +1,17 @@
---
title: Maven 教程之 settings.xml 详解
-categories:
- - 编程
+date: 2019-05-14 14:57:33
+order: 03
+categories:
- Java
- 软件
- 构建
-tags:
+ - Maven
+tags:
- Java
- 构建
- Maven
-abbrlink: e9105404
-date: 2019-05-14 14:57:33
-permalink: /pages/d05c38/
+permalink: /pages/1d58f1/
---
# Maven 教程之 settings.xml 详解
@@ -406,4 +406,4 @@ maven 插件是一种特殊类型的构件。由于这个原因,插件仓库
## 参考资料
-- [maven 官方文档之 settings](https://maven.apache.org/settings.html)
+- [maven 官方文档之 settings](https://maven.apache.org/settings.html)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md" "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
similarity index 94%
rename from "docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
index ee3b4efd..af20c6e4 100644
--- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
@@ -1,17 +1,17 @@
---
title: Maven 实战问题和最佳实践
-categories:
- - 编程
+date: 2018-11-28 09:29:22
+order: 04
+categories:
- Java
- 软件
- 构建
-tags:
+ - Maven
+tags:
- Java
- 构建
- Maven
-abbrlink: 684ab4a9
-date: 2018-11-28 09:29:22
-permalink: /pages/7908f2/
+permalink: /pages/198618/
---
# Maven 实战问题和最佳实践
@@ -48,21 +48,21 @@ maven 的 JDK 源与指定的 JDK 编译版本不符。
Project SDK 是否正确
-
+
SDK 路径是否正确
-
+
- **查看 Settings > Maven 的配置**
JDK for importer 是否正确
-
+
Runner 是否正确
-
+
### 重复引入依赖
@@ -292,4 +292,4 @@ spring-boot-dependencies 的 pom.xml 形式:
-```
+```
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md" "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md"
similarity index 97%
rename from "docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md"
index 32416c41..2f29b940 100644
--- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md"
@@ -1,17 +1,17 @@
---
title: Maven 教程之发布 jar 到私服或中央仓库
-categories:
- - 编程
+date: 2019-05-14 14:57:33
+order: 05
+categories:
- Java
- 软件
- 构建
-tags:
+ - Maven
+tags:
- Java
- 构建
- Maven
-abbrlink: b88f29ef
-date: 2019-05-14 14:57:33
-permalink: /pages/2ddf04/
+permalink: /pages/7bdaf9/
---
# Maven 教程之发布 jar 到私服或中央仓库
@@ -32,7 +32,7 @@ permalink: /pages/2ddf04/
注册账号成功后,根据你 Java 包的功能分别写上`Summary`、`Description`、`Group Id`、`SCM url`以及`Project URL`等必要信息,可以参见我之前创建的 Issue:[OSSRH-36187](https://issues.sonatype.org/browse/OSSRH-36187)。
-
+
创建完之后需要等待 Sonatype 的工作人员审核处理,审核时间还是很快的,我的审核差不多等待了两小时。当 Issue 的 Status 变为`RESOLVED`后,就可以进行下一步操作了。
@@ -308,7 +308,7 @@ gpg: unchanged: 1
进入[官方下载地址](https://www.sonatype.com/download-oss-sonatype),选择合适版本下载。
-
+
本人希望将 Nexus 部署在 Linux 机器,所以选用的是 Unix 版本。
@@ -340,13 +340,13 @@ Usage: ./nexus {start|stop|run|run-redirect|status|restart|force-reload}
启动成功后,在浏览器中访问 `http://:8081`,欢迎页面如下图所示:
-
+
点击右上角 Sign in 登录,默认用户名/密码为:admin/admin123。
有必要提一下的是,在 Nexus 的 Repositories 管理页面,展示了可用的 maven 仓库,如下图所示:
-
+
> 说明:
>
@@ -476,4 +476,4 @@ $ mvn clean deploy -Dmaven.skip.test=true -P zp
- http://www.ruanyifeng.com/blog/2013/07/gpg.html
- https://www.cnblogs.com/hoobey/p/6102382.html
- https://blog.csdn.net/wzygis/article/details/49276779
-- https://blog.csdn.net/clj198606061111/article/details/52200928
+- https://blog.csdn.net/clj198606061111/article/details/52200928
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/06.Maven\346\217\222\344\273\266\344\271\213\344\273\243\347\240\201\346\243\200\346\237\245.md" "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/06.Maven\346\217\222\344\273\266\344\271\213\344\273\243\347\240\201\346\243\200\346\237\245.md"
similarity index 98%
rename from "docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/06.Maven\346\217\222\344\273\266\344\271\213\344\273\243\347\240\201\346\243\200\346\237\245.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/06.Maven\346\217\222\344\273\266\344\271\213\344\273\243\347\240\201\346\243\200\346\237\245.md"
index c1484499..561aa81a 100644
--- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/06.Maven\346\217\222\344\273\266\344\271\213\344\273\243\347\240\201\346\243\200\346\237\245.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/06.Maven\346\217\222\344\273\266\344\271\213\344\273\243\347\240\201\346\243\200\346\237\245.md"
@@ -1,17 +1,17 @@
---
title: Maven 插件之代码检查
-categories:
- - 编程
+date: 2019-12-16 17:09:26
+order: 06
+categories:
- Java
- 软件
- 构建
-tags:
+ - Maven
+tags:
- Java
- 构建
- Maven
-abbrlink: 7b76d24a
-date: 2019-12-16 17:09:26
-permalink: /pages/149013/
+permalink: /pages/370f1d/
---
# Maven 插件之代码检查
@@ -89,7 +89,7 @@ permalink: /pages/149013/
scope: 可以检查的方法的范围,例如:public只能检查public修饰的方法,private可以检查所有的方法
allowMissingParamTags: 是否忽略对参数注释的检查
allowMissingThrowsTags: 是否忽略对throws注释的检查
- allowMissingReturnTag: 是否忽略对return注释的检查 -->
+ allowMissingReturntags: 是否忽略对return注释的检查 -->
@@ -427,4 +427,4 @@ permalink: /pages/149013/
- https://www.jianshu.com/p/557b975ae40d
- 阿里巴巴编程规范
- https://github.com/alibaba/p3c
- - https://github.com/alibaba/p3c/blob/master/p3c-pmd/pom.xml
+ - https://github.com/alibaba/p3c/blob/master/p3c-pmd/pom.xml
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/README.md" "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/README.md"
similarity index 90%
rename from "docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/README.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/README.md"
index 3e7f7d5f..179cb604 100644
--- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/README.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/README.md"
@@ -1,18 +1,18 @@
---
title: Maven 教程
-categories:
- - 编程
+date: 2020-08-04 15:20:54
+categories:
- Java
- 软件
- 构建
-tags:
+ - Maven
+tags:
- Java
- 构建
- Maven
+permalink: /pages/85f27a/
hidden: true
-abbrlink: a96d715
-date: 2020-08-04 15:20:54
-permalink: /pages/14735b/
+index: false
---
# Maven 教程
@@ -46,4 +46,4 @@ permalink: /pages/14735b/
## 🚪 传送
-◾ 🏠 [JAVA-TUTORIAL 首页](https://github.com/dunwu/java-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/02.Ant.md" "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/02.Ant.md"
similarity index 99%
rename from "docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/02.Ant.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/02.Ant.md"
index 19493eb0..d0b8d139 100644
--- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/02.Ant.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/02.Ant.md"
@@ -1,17 +1,16 @@
---
title: Ant 简易教程
-categories:
- - 编程
+date: 2017-12-06 09:46:28
+order: 02
+categories:
- Java
- 软件
- 构建
-tags:
+tags:
- Java
- 构建
- Ant
-abbrlink: 389d1b12
-date: 2017-12-06 09:46:28
-permalink: /pages/e2af3a/
+permalink: /pages/0bafae/
---
# Ant 简易教程
@@ -378,4 +377,4 @@ _——Ant1.8.0 新增特性。_
## 参考资料
- [ant 官方手册](http://ant.apache.org/manual/index.html)
-- [http://www.blogjava.net/amigoxie/archive/2007/11/09/159413.html](http://www.blogjava.net/amigoxie/archive/2007/11/09/159413.html)
+- [http://www.blogjava.net/amigoxie/archive/2007/11/09/159413.html](http://www.blogjava.net/amigoxie/archive/2007/11/09/159413.html)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/README.md" "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/README.md"
similarity index 87%
rename from "docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/README.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/README.md"
index 388ac2d8..08c9c99a 100644
--- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/README.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/README.md"
@@ -1,17 +1,16 @@
---
title: Java 构建
-categories:
- - 编程
+date: 2020-08-04 15:20:54
+categories:
- Java
- 软件
- 构建
-tags:
+tags:
- Java
- 构建
-abbrlink: 7ebcc307
-date: 2020-08-04 15:20:54
+permalink: /pages/d1859b/
hidden: true
-permalink: /pages/95388e/
+index: false
---
# Java 构建
@@ -48,4 +47,4 @@ permalink: /pages/95388e/
## 🚪 传送
-◾ 🏠 [JAVA-TUTORIAL 首页](https://github.com/dunwu/java-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/02.IDE/01.Intellij.md" "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/01.Intellij.md"
similarity index 94%
rename from "docs/11.\350\275\257\344\273\266/02.IDE/01.Intellij.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/02.IDE/01.Intellij.md"
index 66aa6402..85b4f254 100644
--- "a/docs/11.\350\275\257\344\273\266/02.IDE/01.Intellij.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/01.Intellij.md"
@@ -1,16 +1,16 @@
---
title: Intellij IDEA 快速入门
-categories:
- - 编程
+date: 2019-11-29 18:10:14
+order: 01
+categories:
- Java
- 软件
- IDE
-tags:
+tags:
- Java
- IDE
-abbrlink: a688dbc5
-date: 2019-11-29 18:10:14
-permalink: /pages/ea83ee/
+ - Intellij
+permalink: /pages/ac5c6a/
---
# Intellij IDEA 快速入门
@@ -200,10 +200,10 @@ IntelliJ IDEA 作为一个以快捷键为中心的 IDE,为大多数操作建
#### VCS/Local History
| 快捷键 | 介绍 |
-| --------------- | -------------------------------------------------- | ---------------------------------------- |
+| --------------- | -------------------------------------------------- |
| Ctrl + K | 版本控制提交项目,需要此项目有加入到版本控制才可用 |
| Ctrl + T | 版本控制更新项目,需要此项目有加入到版本控制才可用 |
-| `Alt + | ` | 显示版本控制常用操作菜单弹出层`(必备)` |
+| `Alt + |` | 显示版本控制常用操作菜单弹出层`(必备)` |
| Alt + Shift + C | 查看最近操作项目的变化情况列表 |
| Alt + Shift + N | 选择/添加 task`(必备)` |
@@ -256,29 +256,23 @@ IntelliJ IDEA 作为一个以快捷键为中心的 IDE,为大多数操作建
[下载地址](https://github.com/altercation/solarized)
-## 破解
+## FAQ
-Intellij 是一个收费的 IDE,坦白说有点小贵,买不起。
+(1)运行时报错
-所以,很惭愧,只好用下破解方法了。网上有很多使用注册码的网文,但是注册码不稳定,随时可能被封。还是自行搭建一个注册服务器比较稳定。我使用了 [ilanyu](http://blog.lanyus.com/) 博文 [IntelliJ IDEA License Server 本地搭建教程](http://blog.lanyus.com/archives/174.html) 的方法,亲测十分有效。
+> Error running XXX. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun
-我的备用地址:[百度云盘](https://yun.baidu.com/disk/home?#list/vmode=list&path=%2F%E8%BD%AF%E4%BB%B6%2F%E5%BC%80%E5%8F%91%E8%BD%AF%E4%BB%B6%2FIDE)
+解决方案:
-下载并解压文中的压缩包到本地,选择适合操作系统的版本运行。
+找到 `.idea/libraies/workspace.xml` 中的 ``
-如果是在 Linux 上运行,推荐创建一个脚本,代码如下:
+添加一行配置:
-```bash
-# 使用 nohup 创建守护进程,运行 IntelliJIDEALicenseServer_linux_amd64
-# 如果运行在其他 Linux 发行版本,替换执行的脚本即可
-nohup sh IntelliJIDEALicenseServer_linux_amd64 2>&1
+```xml
+
```
-这样做是因为:大部分人使用 linux 是使用仿真器连接虚拟机,如果断开连接,进程也会被 kill,每次启动这个注册服务器很麻烦不是吗?而启动了守护进程,则不会出现这种情况,只有你主动 kill 进程才能将其干掉。
-
-Windows 版本是 exe 程序,将其设为开机自动启动即可,别告诉我你不知道怎么设置开机自动启动。
-
## 参考资料
- [IntelliJ-IDEA-Tutorial](https://github.com/judasn/IntelliJ-IDEA-Tutorial)
-- [极客学院 - Intellij IDEA 使用教程](http://wiki.jikexueyuan.com/project/intellij-idea-tutorial/)
+- [极客学院 - Intellij IDEA 使用教程](http://wiki.jikexueyuan.com/project/intellij-idea-tutorial/)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/02.IDE/02.Eclipse.md" "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/02.Eclipse.md"
similarity index 99%
rename from "docs/11.\350\275\257\344\273\266/02.IDE/02.Eclipse.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/02.IDE/02.Eclipse.md"
index e75751cc..d8f3730d 100644
--- "a/docs/11.\350\275\257\344\273\266/02.IDE/02.Eclipse.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/02.Eclipse.md"
@@ -1,16 +1,15 @@
---
title: Eclipse 快速入门
-categories:
- - 编程
+date: 2018-07-01 11:27:47
+order: 02
+categories:
- Java
- 软件
- IDE
-tags:
+tags:
- Java
- IDE
-abbrlink: bd5534bf
-date: 2018-07-01 11:27:47
-permalink: /pages/a897a9/
+permalink: /pages/2257c7/
---
# Eclipse 快速入门
@@ -245,4 +244,4 @@ http://tomcat.apache.org/download-70.cgi这里有Tomcat的安装包和源码包
| Ctrl+T | 快速显示当前类的继承结构 |
| Ctrl+W | 关闭当前 Editer |
| Ctrl+L | 文本编辑器 转至行 |
-| F2 | 显示工具提示描述 |
+| F2 | 显示工具提示描述 |
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/02.IDE/03.VsCode.md" "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/03.VsCode.md"
similarity index 88%
rename from "docs/11.\350\275\257\344\273\266/02.IDE/03.VsCode.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/02.IDE/03.VsCode.md"
index 4cf7ea00..909e80c5 100644
--- "a/docs/11.\350\275\257\344\273\266/02.IDE/03.VsCode.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/03.VsCode.md"
@@ -1,16 +1,15 @@
---
title: Vscode 快速入门
-categories:
- - 编程
+date: 2019-05-14 14:57:33
+order: 03
+categories:
- Java
- 软件
- IDE
-tags:
+tags:
- Java
- IDE
-abbrlink: 849a3ae4
-date: 2019-05-14 14:57:33
-permalink: /pages/a537c7/
+permalink: /pages/0f7153/
---
# Vscode 快速入门
@@ -59,4 +58,4 @@ permalink: /pages/a537c7/
- https://github.com/Microsoft/vscode-docs
- https://github.com/Microsoft/vscode-tips-and-tricks
- 更多资源
- - https://github.com/viatsko/awesome-vscode
+ - https://github.com/viatsko/awesome-vscode
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/02.IDE/README.md" "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/README.md"
similarity index 87%
rename from "docs/11.\350\275\257\344\273\266/02.IDE/README.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/02.IDE/README.md"
index afd8b09b..e487ace7 100644
--- "a/docs/11.\350\275\257\344\273\266/02.IDE/README.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/02.IDE/README.md"
@@ -1,17 +1,16 @@
---
title: Java IDE
-categories:
- - 编程
+date: 2022-02-18 08:53:11
+categories:
- Java
- 软件
- IDE
-tags:
+tags:
- Java
- IDE
-abbrlink: c44dd053
-date: 2022-02-18 08:53:11
+permalink: /pages/8695a7/
hidden: true
-permalink: /pages/2df5ea/
+index: false
---
# Java IDE
@@ -24,4 +23,4 @@ permalink: /pages/2df5ea/
- [Intellij IDEA 快速入门](01.Intellij.md)
- [Eclipse 快速入门](02.Eclipse.md)
-- [Vscode 快速入门](03.VsCode.md)
+- [Vscode 快速入门](03.VsCode.md)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md" "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md"
similarity index 57%
rename from "docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md"
index 2c1d9e94..7ccdb465 100644
--- "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md"
@@ -1,33 +1,32 @@
---
title: 监控工具对比
-categories:
- - 编程
+date: 2020-02-11 17:48:32
+order: 01
+categories:
- Java
- 软件
- 监控诊断
-tags:
+tags:
- Java
- 监控
-abbrlink: 7331d4e5
-date: 2020-02-11 17:48:32
-permalink: /pages/c7c5ec/
+permalink: /pages/16563a/
---
# 监控工具对比
## 监控工具发展史
-
+
## 监控工具比对
### 特性对比
-
+
### 生态对比
-
+
## 技术选型
@@ -39,4 +38,4 @@ permalink: /pages/c7c5ec/
## 参考资料
-[CAT、Zipkin 和 SkyWalking 该如何选型?](https://time.geekbang.org/dailylesson/detail/100028416)
+[CAT、Zipkin 和 SkyWalking 该如何选型?](https://time.geekbang.org/dailylesson/detail/100028416)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md" "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md"
similarity index 94%
rename from "docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md"
index 639d3a9f..ee099d36 100644
--- "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md"
@@ -1,17 +1,16 @@
---
title: CAT 快速入门
-categories:
- - 编程
+date: 2020-02-11 17:48:32
+order: 02
+categories:
- Java
- 软件
- 监控诊断
-tags:
+tags:
- Java
- 监控
- CAT
-abbrlink: 9e5e43a8
-date: 2020-02-11 17:48:32
-permalink: /pages/83e684/
+permalink: /pages/821ca3/
---
# CAT 快速入门
@@ -38,7 +37,7 @@ CAT 监控系统将每次 URL、Service 的请求内部执行情况都封装为
- **Heartbeat** 表示程序内定期产生的统计信息, 如 CPU 利用率, 内存利用率, 连接池状态, 系统负载等
- **Metric** 用于记录业务指标、指标可能包含对一个指标记录次数、记录平均值、记录总和,业务指标最低统计粒度为 1 分钟
-
+
## CAT 部署
@@ -73,7 +72,7 @@ CAT 主要分为三个模块:
在实际开发和部署中,cat-consumer 和 cat-home 是部署在一个 jvm 内部,每个 CAT 服务端都可以作为 consumer 也可以作为 home,这样既能减少整个 CAT 层级结构,也可以增加整个系统稳定性。
-
+
上图是 CAT 目前多机房的整体结构图:
@@ -84,4 +83,4 @@ CAT 主要分为三个模块:
## 参考资料
-- [CAT Github](https://github.com/dianping/cat)
+- [CAT Github](https://github.com/dianping/cat)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md" "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md"
similarity index 97%
rename from "docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md"
index a36e4d17..e665495d 100644
--- "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md"
@@ -1,17 +1,16 @@
---
title: Zipkin 快速入门
-categories:
- - 编程
+date: 2020-03-23 22:56:45
+order: 03
+categories:
- Java
- 软件
- 监控诊断
-tags:
+tags:
- Java
- 监控
- Zipkin
-abbrlink: bed182d4
-date: 2020-03-23 22:56:45
-permalink: /pages/82c168/
+permalink: /pages/0a8826/
---
# Zipkin 快速入门
@@ -30,7 +29,7 @@ Zipkin 基于 Google Dapper 的论文设计而来,由 Twitter 公司开发贡
Zipkin UI 还提供了一个依赖关系图,该关系图显示了每个应用程序中跟踪了多少个请求。这对于识别聚合行为(包括错误路径或对不赞成使用的服务的调用)很有帮助。
-
+
### 多平台
@@ -48,7 +47,7 @@ Zipkin 服务器捆绑了用于采集和存储数据的扩展。
数据以 json 形式存储,可以参考:[Zipkin 官方的 Swagger API](https://zipkin.io/zipkin-api/#/default/post_spans)
-
+
## 二、Zipkin 安装
@@ -94,7 +93,7 @@ ZipKin 可以分为两部分,
架构如下:
-
+
### Zipkin Server
@@ -170,4 +169,4 @@ Instrumented client 和 server 是分别使用了 ZipKin Client 的服务,Zipk
- [Zipkin 官网](https://zipkin.io/)
- [Zipkin Github](https://github.com/openzipkin/zipkin)
-- [brave](https://github.com/openzipkin/brave)
+- [brave](https://github.com/openzipkin/brave)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md" "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md"
similarity index 91%
rename from "docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md"
index e0c84c3e..e3573437 100644
--- "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md"
@@ -1,17 +1,16 @@
---
title: SkyWalking 快速入门
-categories:
- - 编程
+date: 2020-02-07 23:04:47
+order: 04
+categories:
- Java
- 软件
- 监控诊断
-tags:
+tags:
- Java
- 监控
- SkyWalking
-abbrlink: a6f15946
-date: 2020-02-07 23:04:47
-permalink: /pages/d82d3c/
+permalink: /pages/df7dec/
---
# SkyWalking 快速入门
@@ -24,7 +23,7 @@ SkyWalking 是观察性分析平台和应用性能管理系统。
提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案。
-
+
### SkyWalking 特性
@@ -45,7 +44,7 @@ SkyWalking 是观察性分析平台和应用性能管理系统。
从逻辑上讲,SkyWalking 分为四个部分:探针(Probes),平台后端,存储和 UI。
-
+
- **探针(Probes)** - 探针是指集成到目标系统中的代理或 SDK 库。它们负责收集数据(包括跟踪数据和统计数据)并将其按照 SkyWalking 的要求重新格式化为。
- **平台后端** - 平台后端是一个提供后端服务的集群。它用于聚合、分析和驱动从探针到 UI 的流程。它还为传入格式(如 Zipkin 的格式),存储实现程序和集群管理提供可插入功能。 您甚至可以使用 Observability Analysis Language 自定义聚合和分析。
@@ -56,7 +55,7 @@ SkyWalking 是观察性分析平台和应用性能管理系统。
进入 [Apache SkyWalking 官方下载页面](http://skywalking.apache.org/downloads/),选择安装版本,下载解压到本地。
-
+
安装分为三个部分:
@@ -66,4 +65,4 @@ SkyWalking 是观察性分析平台和应用性能管理系统。
## 参考资料
-- [SkyWalking Github](https://github.com/apache/skywalking)
+- [SkyWalking Github](https://github.com/apache/skywalking)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/05.Arthas.md" "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/05.Arthas.md"
similarity index 99%
rename from "docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/05.Arthas.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/05.Arthas.md"
index a8ea212c..7e5726c9 100644
--- "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/05.Arthas.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/05.Arthas.md"
@@ -1,17 +1,16 @@
---
title: Arthas 快速入门
-categories:
- - 编程
+date: 2020-02-07 23:04:47
+order: 05
+categories:
- Java
- 软件
- 监控诊断
-tags:
+tags:
- Java
- 诊断
- Arthas
-abbrlink: e60b19c0
-date: 2020-02-07 23:04:47
-permalink: /pages/b6a542/
+permalink: /pages/c689d1/
---
# Arthas 快速入门
@@ -425,4 +424,4 @@ Arthas 支持使用管道对上述命令的结果进行进一步的处理,如`
- [Arthas Github](https://github.com/alibaba/arthas)
- [Arthas 用户文档](https://alibaba.github.io/arthas/index.html)
-- [arthas 源码分析](https://www.jianshu.com/p/4e34d0ab47d1)
+- [arthas 源码分析](https://www.jianshu.com/p/4e34d0ab47d1)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/README.md" "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/README.md"
similarity index 80%
rename from "docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/README.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/README.md"
index 693f6ddb..a2caaea0 100644
--- "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/README.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/README.md"
@@ -1,17 +1,17 @@
---
title: Java 监控诊断
-categories:
- - 编程
+date: 2020-02-11 17:48:32
+categories:
- Java
- 软件
- 监控诊断
-tags:
+tags:
- Java
- 监控
- 诊断
-abbrlink: 7af21817
-date: 2020-02-11 17:48:32
-permalink: /pages/2853ec/
+permalink: /pages/3d16d3/
+hidden: true
+index: false
---
# Java 监控诊断
@@ -30,4 +30,4 @@ permalink: /pages/2853ec/
- [Zipkin Github](https://github.com/openzipkin/zipkin)
- [SkyWalking Github](https://github.com/apache/skywalking)
- [PinPoint Github](https://github.com/naver/pinpoint)
-- [Arthas Github](https://github.com/alibaba/arthas)
+- [Arthas Github](https://github.com/alibaba/arthas)
\ No newline at end of file
diff --git "a/docs/11.\350\275\257\344\273\266/README.md" "b/docs/01.Java/11.\350\275\257\344\273\266/README.md"
similarity index 93%
rename from "docs/11.\350\275\257\344\273\266/README.md"
rename to "docs/01.Java/11.\350\275\257\344\273\266/README.md"
index 2e52122f..d44fbe38 100644
--- "a/docs/11.\350\275\257\344\273\266/README.md"
+++ "b/docs/01.Java/11.\350\275\257\344\273\266/README.md"
@@ -1,16 +1,14 @@
---
title: Java 软件
-categories:
- - 编程
+date: 2022-02-18 08:53:11
+categories:
- Java
- 软件
- - IDE
-tags:
+tags:
- Java
-abbrlink: bd90f980
-date: 2022-02-18 08:53:11
+permalink: /pages/2cb045/
hidden: true
-permalink: /pages/dab057/
+index: false
---
# Java 软件
@@ -69,4 +67,4 @@ permalink: /pages/dab057/
## 🚪 传送
-◾ 🏠 [JAVA-TUTORIAL 首页](https://github.com/dunwu/java-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/01.IO/01.JSON\345\272\217\345\210\227\345\214\226.md" "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/01.JSON\345\272\217\345\210\227\345\214\226.md"
similarity index 99%
rename from "docs/12.\345\267\245\345\205\267/01.IO/01.JSON\345\272\217\345\210\227\345\214\226.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/01.IO/01.JSON\345\272\217\345\210\227\345\214\226.md"
index 4cf5ca34..2e3cfea8 100644
--- "a/docs/12.\345\267\245\345\205\267/01.IO/01.JSON\345\272\217\345\210\227\345\214\226.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/01.JSON\345\272\217\345\210\227\345\214\226.md"
@@ -1,18 +1,17 @@
---
title: Java 和 JSON 序列化
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 01
+categories:
- Java
- 工具
- IO
-tags:
+tags:
- Java
- IO
- 序列化
- JSON
-abbrlink: 37e168b9
-date: 2022-02-17 22:34:30
-permalink: /pages/a14952/
+permalink: /pages/4622a6/
---
# Java 和 JSON 序列化
@@ -483,4 +482,4 @@ private class SomeObject {
-
- [json 的 RFC 文档](http://tools.ietf.org/html/rfc4627)
- [JSON 最佳实践](https://kimmking.github.io/2017/06/06/json-best-practice/)
- - [【简明教程】JSON](https://www.jianshu.com/p/8b428e1d1564)
+ - [【简明教程】JSON](https://www.jianshu.com/p/8b428e1d1564)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/01.IO/02.\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226.md" "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/02.\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226.md"
similarity index 82%
rename from "docs/12.\345\267\245\345\205\267/01.IO/02.\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/01.IO/02.\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226.md"
index 99670f4a..631a5fcb 100644
--- "a/docs/12.\345\267\245\345\205\267/01.IO/02.\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/02.\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226.md"
@@ -1,18 +1,17 @@
---
title: Java 二进制序列化
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 02
+categories:
- Java
- 工具
- IO
-tags:
+tags:
- Java
- IO
- 序列化
- 二进制
-abbrlink: 7684267f
-date: 2022-02-17 22:34:30
-permalink: /pages/95f25b/
+permalink: /pages/08d872/
---
# Java 二进制序列化
@@ -23,7 +22,7 @@ permalink: /pages/95f25b/
原因很简单,就是 Java 默认的序列化机制(`ObjectInputStream` 和 `ObjectOutputStream`)具有很多缺点。
-> 不了解 Java 默认的序列化机制,可以参考:[Java 序列化](https://dunwu.github.io/blog/pages/2b2f0f/)
+> 不了解 Java 默认的序列化机制,可以参考:[Java 序列化](https://dunwu.github.io/waterdrop/pages/2b2f0f/)
Java 自身的序列化方式具有以下缺点:
@@ -38,15 +37,23 @@ Java 自身的序列化方式具有以下缺点:
#### Protobuf
-[Protobuf](https://developers.google.com/protocol-buffers/) 是 Google 开发的结构序列化库。
+[Protobuf](https://developers.google.com/protocol-buffers/) 是 Google 公司内部的混合语言数据标准,是一种轻便、高效的结构化数据存储
+格式,可以用于结构化数据序列化,支持 Java、Python、C++、Go 等语言。Protobuf
+使用的时候需要定义 IDL(Interface description language),然后使用不同语言的 IDL
+编译器,生成序列化工具类。
-它具有以下特性:
+优点:
-- 结构化数据存储格式(xml,json 等)
-- 高性能编解码技术
-- 语言和平台无关,扩展性好
+- 序列化后体积相比 JSON、Hessian 小很多
+- 序列化反序列化速度很快,不需要通过反射获取类型
+- 语言和平台无关(基于 IDL),IDL 能清晰地描述语义,所以足以帮助并保证应用程序之间的类型不会丢失,无需类似 XML 解析器
+- 消息格式升级和兼容性不错,可以做到后向兼容
- 支持 Java, C++, Python 三种语言
+缺点:
+
+- Protobuf 对于具有反射和动态能力的语言来说,用起来很费劲。
+
#### Thrift
> [Thrift](https://github.com/apache/thrift) 是 apache 开源项目,是一个点对点的 RPC 实现。
@@ -59,15 +66,23 @@ Java 自身的序列化方式具有以下缺点:
#### Hessian
-> [Hessian](http://hessian.caucho.com/) 是一种二进制传输协议。
->
-> RPC 框架 Dubbo 就支持 Thrift 和 Hession。
+[Hessian](http://hessian.caucho.com/) 是动态类型、二进制、紧凑的,并且可跨语言移植的一种序列化框架。Hessian 协
+议要比 JDK、JSON 更加紧凑,性能上要比 JDK、JSON 序列化高效很多,而且生成的字节
+数也更小。
+
+RPC 框架 Dubbo 就支持 Thrift 和 Hession。
它具有以下特性:
- 支持多种语言。如:Java、Python、C++、C#、PHP、Ruby 等。
- 相对其他二进制序列化库较慢。
+Hessian 本身也有问题,官方版本对 Java 里面一些常见对象的类型不支持:
+
+- Linked 系列,LinkedHashMap、LinkedHashSet 等,但是可以通过扩展 CollectionDeserializer 类修复;
+- Locale 类,可以通过扩展 ContextSerializerFactory 类修复;
+- Byte/Short 反序列化的时候变成 Integer。
+
#### Kryo
> [Kryo](https://github.com/EsotericSoftware/kryo) 是用于 Java 的快速高效的二进制对象图序列化框架。Kryo 还可以执行自动的深拷贝和浅拷贝。 这是从对象到对象的直接复制,而不是从对象到字节的复制。
@@ -342,6 +357,27 @@ long end = System.currentTimeMillis();
System.out.printf("Kryo 序列化/反序列化耗时:%s", (end - begin));
```
+Hessian 应用
+
+```java
+Student student = new Student();
+student.setNo(101);
+student.setName("HESSIAN");
+//把student对象转化为byte数组
+ByteArrayOutputStream bos = new ByteArrayOutputStream();
+Hessian2Output output = new Hessian2Output(bos);
+output.writeObject(student);
+output.flushBuffer();
+byte[] data = bos.toByteArray();
+bos.close();
+//把刚才序列化出来的byte数组转化为student对象
+ByteArrayInputStream bis = new ByteArrayInputStream(data);
+Hessian2Input input = new Hessian2Input(bis);
+Student deStudent = (Student) input.readObject();
+input.close();
+System.out.println(deStudent);
+```
+
## 参考资料
- **官方**
@@ -352,4 +388,4 @@ System.out.printf("Kryo 序列化/反序列化耗时:%s", (end - begin));
- [Hessian 官网](http://hessian.caucho.com/)
- [FST Github](https://github.com/RuedigerMoeller/fast-serialization)
- **文章**
- - [java 序列化框架对比](https://www.jianshu.com/p/937883b6b2e5)
+ - [java 序列化框架对比](https://www.jianshu.com/p/937883b6b2e5)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/01.IO/README.md" "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/README.md"
similarity index 90%
rename from "docs/12.\345\267\245\345\205\267/01.IO/README.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/01.IO/README.md"
index 443ade0d..1cd5ba95 100644
--- "a/docs/12.\345\267\245\345\205\267/01.IO/README.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/01.IO/README.md"
@@ -1,23 +1,22 @@
---
title: Java 序列化工具
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+categories:
- Java
- 工具
- IO
-tags:
+tags:
- Java
- IO
- 序列化
-abbrlink: 53c50fed
-date: 2022-02-17 22:34:30
+permalink: /pages/08b504/
hidden: true
-permalink: /pages/0358e9/
+index: false
---
# Java 序列化工具
-Java 官方的序列化存在许多问题,因此,很多人更愿意使用优秀的第三方序列化工具来替代 Java 自身的序列化机制。 如果想详细了解 Java 自身序列化方式,可以参考:[Java 序列化](https://dunwu.github.io/blog/pages/2b2f0f/)
+Java 官方的序列化存在许多问题,因此,很多人更愿意使用优秀的第三方序列化工具来替代 Java 自身的序列化机制。 如果想详细了解 Java 自身序列化方式,可以参考:[Java 序列化](https://dunwu.github.io/waterdrop/pages/2b2f0f/)
序列化库技术选型:
@@ -37,4 +36,4 @@ Java 官方的序列化存在许多问题,因此,很多人更愿意使用优
- [Hessian 官网](http://hessian.caucho.com/doc/hessian-overview.xtp)
- [Fastjson Github](https://github.com/alibaba/fastjson)
- [Jackson Github](https://github.com/FasterXML/jackson)
-- [Gson Github](https://github.com/google/gson)
+- [Gson Github](https://github.com/google/gson)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/02.JavaBean/01.Lombok.md" "b/docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/01.Lombok.md"
similarity index 99%
rename from "docs/12.\345\267\245\345\205\267/02.JavaBean/01.Lombok.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/01.Lombok.md"
index 8c48c43a..39b1df3a 100644
--- "a/docs/12.\345\267\245\345\205\267/02.JavaBean/01.Lombok.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/01.Lombok.md"
@@ -1,17 +1,16 @@
---
title: Lombok 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 01
+categories:
- Java
- 工具
- JavaBean
-tags:
+tags:
- Java
- JavaBean
- Lombok
-abbrlink: 6f8c7136
-date: 2022-02-17 22:34:30
-permalink: /pages/0d31cd/
+permalink: /pages/eb1d46/
---
# Lombok 快速入门
@@ -534,4 +533,4 @@ public void testEqualsAndHashCodeDemo() {
- [Lombok 官网](https://projectlombok.org/)
- [Lombok Github](https://github.com/rzwitserloot/lombok)
-- [IntelliJ IDEA - Lombok Plugin](http://plugins.jetbrains.com/plugin/6317-lombok-plugin)
+- [IntelliJ IDEA - Lombok Plugin](http://plugins.jetbrains.com/plugin/6317-lombok-plugin)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/02.JavaBean/02.Dozer.md" "b/docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/02.Dozer.md"
similarity index 99%
rename from "docs/12.\345\267\245\345\205\267/02.JavaBean/02.Dozer.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/02.Dozer.md"
index 4870defd..e9a7c230 100644
--- "a/docs/12.\345\267\245\345\205\267/02.JavaBean/02.Dozer.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/02.JavaBean/02.Dozer.md"
@@ -1,17 +1,16 @@
---
title: Dozer 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 02
+categories:
- Java
- 工具
- JavaBean
-tags:
+tags:
- Java
- JavaBean
- Dozer
-abbrlink: 3632a3b1
-date: 2022-02-17 22:34:30
-permalink: /pages/596174/
+permalink: /pages/45e21b/
---
# Dozer 快速入门
@@ -787,4 +786,4 @@ superAttribute 和 superAttr 的映射规则会被子类所继承,所以不必
## 参考
-[Dozer 官方文档](http://dozer.sourceforge.net/documentation/gettingstarted.html) | [Dozer 源码地址](https://github.com/DozerMapper/dozer)
+[Dozer 官方文档](http://dozer.sourceforge.net/documentation/gettingstarted.html) | [Dozer 源码地址](https://github.com/DozerMapper/dozer)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md" "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md"
similarity index 98%
rename from "docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md"
index a36c7028..8de94dbc 100644
--- "a/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md"
@@ -1,17 +1,16 @@
---
title: Freemark 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 01
+categories:
- Java
- 工具
- 模板引擎
-tags:
+tags:
- Java
- 模板引擎
- Freemark
-abbrlink: 468afcee
-date: 2022-02-17 22:34:30
-permalink: /pages/34ec25/
+permalink: /pages/a60ccf/
---
# Freemark 快速入门
@@ -35,7 +34,7 @@ Freemark 模板一句话概括就是:**_`模板 + 数据模型 = 输出`_**
- **FTL 标签**:FTL 标签和 HTML 标签很相似,但是它们却是给 FreeMarker 的指示, 而且不会打印在输出内容中。
- **注释**:注释和 HTML 的注释也很相似,但它们是由 `<#--` 和 `-->`来分隔的。注释会被 FreeMarker 直接忽略, 更不会在输出内容中显示。
-
+
> 🔔 注意:
>
@@ -173,4 +172,4 @@ FTL 支持的所有转义字符:
- [Freemark Github](https://github.com/apache/freemarker)
- [Freemark 中文教程](http://freemarker.foofun.cn/)
-- [在线 Freemark 工具](https://try.freemarker.apache.org/)
+- [在线 Freemark 工具](https://try.freemarker.apache.org/)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/02.Thymeleaf.md" "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/02.Thymeleaf.md"
similarity index 99%
rename from "docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/02.Thymeleaf.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/02.Thymeleaf.md"
index 7ea9607a..df2e8fc4 100644
--- "a/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/02.Thymeleaf.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/02.Thymeleaf.md"
@@ -1,17 +1,16 @@
---
title: Thymeleaf 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 02
+categories:
- Java
- 工具
- 模板引擎
-tags:
+tags:
- Java
- 模板引擎
- Thymeleaf
-abbrlink: 33db93c3
-date: 2022-02-17 22:34:30
-permalink: /pages/2263fb/
+permalink: /pages/e7d2ad/
---
# Thymeleaf 快速入门
@@ -481,4 +480,4 @@ TODO
- [Thymeleaf 官网](https://www.thymeleaf.org/)
- [Thymeleaf Github](https://github.com/thymeleaf/thymeleaf/)
-- [Thymeleaf 教程](https://fanlychie.github.io/post/thymeleaf.html)
+- [Thymeleaf 教程](https://fanlychie.github.io/post/thymeleaf.html)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/03.Velocity.md" "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/03.Velocity.md"
similarity index 98%
rename from "docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/03.Velocity.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/03.Velocity.md"
index e83961e4..ccb6514f 100644
--- "a/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/03.Velocity.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/03.Velocity.md"
@@ -1,17 +1,16 @@
---
title: Velocity 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 03
+categories:
- Java
- 工具
- 模板引擎
-tags:
+tags:
- Java
- 模板引擎
- Velocity
-abbrlink: bed8d6a9
-date: 2022-02-17 22:34:30
-permalink: /pages/7ecb81/
+permalink: /pages/3ba0ff/
---
# Velocity 快速入门
@@ -329,4 +328,4 @@ Send me
- [Velocity Github](https://github.com/apache/velocity-engine/)
- [Velocity 官网](https://velocity.apache.org/)
- [Velocity 中文文档](https://wizardforcel.gitbooks.io/velocity-doc/content/)
-- [velocity-spring-boot-project](https://github.com/alibaba/velocity-spring-boot-project)
+- [velocity-spring-boot-project](https://github.com/alibaba/velocity-spring-boot-project)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/README.md" "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/README.md"
similarity index 95%
rename from "docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/README.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/README.md"
index 605d4815..ffd80ba3 100644
--- "a/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/README.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/README.md"
@@ -1,17 +1,16 @@
---
title: Java 模板引擎
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+categories:
- Java
- 工具
- 模板引擎
-tags:
+tags:
- Java
- 模板引擎
-abbrlink: d29d234e
-date: 2022-02-17 22:34:30
+permalink: /pages/9d37fa/
hidden: true
-permalink: /pages/9a5880/
+index: false
---
# Java 模板引擎
@@ -56,4 +55,4 @@ permalink: /pages/9a5880/
- [Velocity Github](https://github.com/apache/velocity-engine/)
- [Velocity 官网](https://velocity.apache.org/)
- [Velocity 中文文档](https://wizardforcel.gitbooks.io/velocity-doc/content/)
- - [velocity-spring-boot-project](https://github.com/alibaba/velocity-spring-boot-project)
+ - [velocity-spring-boot-project](https://github.com/alibaba/velocity-spring-boot-project)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md" "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md"
similarity index 92%
rename from "docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md"
index defa29af..b1d02cb9 100644
--- "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md"
@@ -1,24 +1,35 @@
---
title: JUnit5 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 01
+categories:
- Java
- 工具
- 测试
-tags:
+tags:
- Java
- 测试
- JUnit
-abbrlink: e85f4bbe
-date: 2022-02-17 22:34:30
-permalink: /pages/06533c/
+permalink: /pages/b39f47/
---
# JUnit5 快速入门
-> version: junit5
+## JUnit5 简介
+
+与以前的 JUnit 版本不同,JUnit 5 由来自三个不同子项目的几个不同模块组成。
+
+JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
+
+JUnit Platform 是在 JVM 上启动测试框架的基础。它还定义了用于开发在平台上运行的测试框架的 TestEngine API。此外,该平台还提供了一个控制台启动器,用于从命令行启动平台,并提供 JUnit 平台套件引擎,用于使用平台上的一个或多个测试引擎运行自定义测试套件。
-## 安装
+JUnit Jupiter 是编程模型和扩展模型的组合,用于在 JUnit 5 中编写测试和扩展。Jupiter 子项目提供了一个 测试引擎(`TestEngine` )用于在平台上运行基于 Jupiter 的测试。
+
+JUnit Vintage 提供了一个测试引擎(`TestEngine` ),用于在平台上运行基于 JUnit 3 和 JUnit 4 的测试。它要求 JUnit 4.12 或更高版本。
+
+JUnit 5 在运行时需要 Java 8(或更高版本)。
+
+## JUnit5 安装
在 pom 中添加依赖
@@ -51,9 +62,9 @@ permalink: /pages/06533c/
组件间依赖关系:
-
+
-## JUnit 注解
+## JUnit5 注解
| Annotation | Description |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -73,7 +84,11 @@ permalink: /pages/06533c/
| `@Disabled` | Used to _disable_ a test class or test method; analogous to JUnit 4’s `@Ignore`. Such annotations are not _inherited_. |
| `@ExtendWith` | Used to register custom [extensions](https://junit.org/junit5/docs/current/user-guide/#extensions). Such annotations are _inherited_. |
-## 编写单元测试
+## JUnit5 示例
+
+> 我将一部分官方示例放在了我的个人项目中,可以直接下载测试。
+>
+> 示例源码路径:https://github.com/dunwu/java-tutorial/tree/master/codes/javatech/javatech-lib/src/test/java/io/github/dunwu/javatech/test/junit5
### 基本的单元测试类和方法
@@ -571,10 +586,9 @@ void palindromes(String candidate) {
}
```
-## 引用和引申
+## 参考资料
-- [Github](https://github.com/junit-team/junit5)
-- [官方用户手册](https://junit.org/junit5/docs/current/user-guide/)
-- [Javadoc](https://junit.org/junit5/docs/current/api/)
-- [版本声明](https://junit.org/junit5/docs/current/release-notes/)
-- [官方示例](https://github.com/junit-team/junit5-samples)
+- [Junit5 Github](https://github.com/junit-team/junit5)
+- [Junit5 官方用户手册](https://junit.org/junit5/docs/current/user-guide/)
+- [Junit5 Javadoc](https://junit.org/junit5/docs/current/api/)
+- [Junit5 官方示例](https://github.com/junit-team/junit5-samples)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/02.Mockito.md" "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/02.Mockito.md"
similarity index 99%
rename from "docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/02.Mockito.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/02.Mockito.md"
index 6eae9846..e33ffaa4 100644
--- "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/02.Mockito.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/02.Mockito.md"
@@ -1,17 +1,16 @@
---
title: Mockito 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 02
+categories:
- Java
- 工具
- 测试
-tags:
+tags:
- Java
- 测试
- Mockito
-abbrlink: 6d4202df
-date: 2022-02-17 22:34:30
-permalink: /pages/ab18ad/
+permalink: /pages/f2c6f5/
---
# Mockito 快速入门
@@ -575,4 +574,4 @@ class FooWraper {
- [官网](https://site.mockito.org/)
- [Github](https://github.com/mockito/mockito)
-- [使用强大的 Mockito 测试框架来测试你的代码](https://github.com/xitu/gold-miner/blob/master/TODO/Unit-tests-with-Mockito.md)
+- [使用强大的 Mockito 测试框架来测试你的代码](https://github.com/xitu/gold-miner/blob/master/TODO/Unit-tests-with-Mockito.md)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md" "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md"
similarity index 89%
rename from "docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md"
index e1649bff..7378e09f 100644
--- "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md"
@@ -1,17 +1,16 @@
---
title: JMeter 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 03
+categories:
- Java
- 工具
- 测试
-tags:
+tags:
- Java
- 测试
- JMeter
-abbrlink: 808e762c
-date: 2022-02-17 22:34:30
-permalink: /pages/d99171/
+permalink: /pages/0e5ab1/
---
# JMeter 快速入门
@@ -45,7 +44,7 @@ Jmeter 的工作原理是仿真用户向服务器发送请求,并收集服务
Jmeter 的工作流如下图所示:
-
+
### 主要元素
@@ -65,7 +64,7 @@ Jmeter 的主要元素如下:
- **`预处理器元素(Pre-Processor Elements)`** - 预处理器元素在采样器发出请求之前执行,如果预处理器附加到采样器元素,那么它将在该采样器元素运行之前执行。预处理器元素用于在运行之前准备环境及参数。
- **`后处理器元素(Post-Processor Elements)`** - 后处理器元素是在发送采样器请求之后执行的元素,常用于处理响应数据。
-
+
> 📌 提示:
>
@@ -99,7 +98,7 @@ Jmeter 的主要元素如下:
Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat`
-
+
## 使用
@@ -117,7 +116,7 @@ Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat`
- 设置线程数和循环次数
-
+
#### 配置原件
@@ -125,7 +124,7 @@ Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat`
- 填写协议、服务器名称或 IP、端口号
-
+
#### 构造 HTTP 请求
@@ -135,35 +134,35 @@ Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat`
- 填写方法、路径
- 填写参数、消息体数据、文件上传
-
+
#### 添加 HTTP 请求头
- 在“线程组”上右键 【添加】=>【配置元件】=>【HTTP 信息头管理器】
- 由于我的测试例中传输的数据为 json 形式,所以设置键值对 `Content-Type`:`application/json`
-
+
#### 添加断言
- 在“线程组”上右键 【添加】=>【断言】=>【 响应断言 】
- 在我的案例中,以 HTTP 应答状态码为 200 来判断请求是否成功
-
+
#### 添加察看结果树
- 在“线程组”上右键 【添加】=>【监听器】=>【察看结果树】
- 直接点击运行,就可以查看测试结果
-
+
#### 添加汇总报告
- 在“线程组”上右键 【添加】=>【监听器】=>【汇总报告】
- 直接点击运行,就可以查看测试结果
-
+
#### 保存测试计划
@@ -181,7 +180,7 @@ jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
执行测试计划后,在 `-e -o` 参数后指定的 web 报告目录下,可以找到测试报告内容。在浏览器中打开 `index.html` 文件,可以看到如下报告:
-
+
## 问题
@@ -193,7 +192,7 @@ jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
配置如下所示:
-
+
重要配置说明(其他配置根据实际情况填):
@@ -217,4 +216,4 @@ jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
- [Jmeter Github](https://github.com/apache/jmeter)
- [Jmeter 性能测试入门](https://www.cnblogs.com/TankXiao/p/4045439.html)
- [易百教程 - Jmeter 教程](https://www.yiibai.com/jmeter)
-- [Jmeter 读取本地 txt/csv 文件作为请求参数,实现接口自动化](https://www.jianshu.com/p/3b2d3b643415)
+- [Jmeter 读取本地 txt/csv 文件作为请求参数,实现接口自动化](https://www.jianshu.com/p/3b2d3b643415)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/04.JMH.md" "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/04.JMH.md"
similarity index 99%
rename from "docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/04.JMH.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/04.JMH.md"
index f28a9ae6..e5707faf 100644
--- "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/04.JMH.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/04.JMH.md"
@@ -1,17 +1,16 @@
---
title: JMH 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 04
+categories:
- Java
- 工具
- 测试
-tags:
+tags:
- Java
- 测试
- JUnit
-abbrlink: 293b6b64
-date: 2022-02-17 22:34:30
-permalink: /pages/747d3e/
+permalink: /pages/9c6402/
---
# JMH 快速入门
@@ -353,4 +352,4 @@ State 用于声明某个类是一个“状态”,然后接受一个 Scope 参
- [jmh 官方示例](http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/)
- [Java 微基准测试框架 JMH](https://www.xncoding.com/2018/01/07/java/jmh.html)
-- [JAVA 拾遗 — JMH 与 8 个测试陷阱](https://www.cnkirito.moe/java-jmh/)
+- [JAVA 拾遗 — JMH 与 8 个测试陷阱](https://www.cnkirito.moe/java-jmh/)
\ No newline at end of file
diff --git "a/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/README.md" "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/README.md"
new file mode 100644
index 00000000..ab247b86
--- /dev/null
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/README.md"
@@ -0,0 +1,23 @@
+---
+title: Java 测试
+date: 2022-02-17 22:34:30
+categories:
+ - Java
+ - 工具
+ - 测试
+tags:
+ - Java
+ - 测试
+permalink: /pages/2cecc3/
+hidden: true
+index: false
+---
+
+# Java 测试
+
+## 内容
+
+- [Junit](01.Junit.md)
+- [Mockito](02.Mockito.md)
+- [Jmeter](03.Jmeter.md)
+- [JMH](04.JMH.md)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md" "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md"
similarity index 97%
rename from "docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md"
index c37498e5..efdc23d6 100644
--- "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md"
@@ -1,15 +1,15 @@
---
title: javalib-log
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 01
+categories:
- Java
- 工具
-tags:
+ - 其他
+tags:
- Java
- 日志
-abbrlink: da18907e
-date: 2022-02-17 22:34:30
-permalink: /pages/337701/
+permalink: /pages/fcc1c4/
---
# 细说 Java 主流日志工具库
@@ -64,7 +64,7 @@ logback 当前分成三个模块:`logback-core`、`logback-classic` 和 `logba
Log4j2 架构:
-
+
### Log4j vs Logback vs Log4j2
@@ -108,7 +108,7 @@ common-logging 的功能是提供日志功能的 API 接口,本身并不提供
[官网地址](http://www.slf4j.org/)
-
+
### common-logging vs slf4j
@@ -202,7 +202,7 @@ _slf4j-jdk14-1.7.21.jar_ 会自动将 _slf4j-api-1.7.21.jar_ 也添加到你的
假如你正在开发应用程序所调用的组件当中已经使用了 common-logging,这时你需要 jcl-over-slf4j.jar 把日志信息输出重定向到 slf4j-api,slf4j-api 再去调用 slf4j 实际依赖的日志组件。这个过程称为桥接。下图是官方的 slf4j 桥接策略图:
-
+
从图中应该可以看出,无论你的老项目中使用的是 common-logging 或是直接使用 log4j、java.util.logging,都可以使用对应的桥接 jar 包来解决兼容问题。
@@ -418,7 +418,7 @@ log4j2 基本配置形式如下:
- 要点
- 它有 ``、``、`` 三个子元素。
-
+
### ``
@@ -456,7 +456,7 @@ log4j2 基本配置形式如下:
- 属性
- class:设置具体的实例化类。
-
+
### ``
@@ -742,4 +742,4 @@ log4j 的配置文件一般有 xml 格式或 properties 格式。这里为了和
- [logback 官方文档](http://logback.qos.ch/)
- [log4j 官方文档](http://logging.apache.org/log4j/1.2/)
- [commons-logging 官方文档](http://commons.apache.org/proper/commons-logging/)
--
+-
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/02.Java\345\267\245\345\205\267\345\214\205.md" "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/02.Java\345\267\245\345\205\267\345\214\205.md"
similarity index 73%
rename from "docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/02.Java\345\267\245\345\205\267\345\214\205.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/02.Java\345\267\245\345\205\267\345\214\205.md"
index fb12c3eb..192f3c42 100644
--- "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/02.Java\345\267\245\345\205\267\345\214\205.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/02.Java\345\267\245\345\205\267\345\214\205.md"
@@ -1,15 +1,15 @@
---
title: javalib-util
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 02
+categories:
- Java
- 工具
-tags:
+ - 其他
+tags:
- Java
- 工具包
-abbrlink: 8280ff5f
-date: 2022-02-17 22:34:30
-permalink: /pages/14e432/
+permalink: /pages/27ad42/
---
# 细说 Java 主流工具包
@@ -18,4 +18,4 @@ permalink: /pages/14e432/
- [commons-lang](https://github.com/apache/commons-lang)
- [commons-collections](https://github.com/apache/commons-collections)
- [common-io](https://github.com/apache/commons-io)
-- [guava](https://github.com/google/guava)
+- [guava](https://github.com/google/guava)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/03.Reflections.md" "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/03.Reflections.md"
similarity index 97%
rename from "docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/03.Reflections.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/03.Reflections.md"
index de422ac1..6200ebea 100644
--- "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/03.Reflections.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/03.Reflections.md"
@@ -1,16 +1,16 @@
---
title: Reflections 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 03
+categories:
- Java
- 工具
-tags:
+ - 其他
+tags:
- Java
- 反射
- Reflections
-abbrlink: 3e51d2b2
-date: 2022-02-17 22:34:30
-permalink: /pages/ea4914/
+permalink: /pages/ce6195/
---
# Reflections 快速入门
@@ -105,4 +105,4 @@ Set listMethodsFromCollectionToBoolean =
withParametersAssignableTo(Collection.class), withReturnType(boolean.class));
Set fields = getAllFields(SomeClass.class, withAnnotation(annotation), withTypeAssignableTo(type));
-```
+```
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/04.JavaMail.md" "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/04.JavaMail.md"
similarity index 99%
rename from "docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/04.JavaMail.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/04.JavaMail.md"
index 1eae960e..dc623bbf 100644
--- "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/04.JavaMail.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/04.JavaMail.md"
@@ -1,15 +1,15 @@
---
title: JavaMail 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 04
+categories:
- Java
- 工具
-tags:
+ - 其他
+tags:
- Java
- 邮件
-abbrlink: 83e73e
-date: 2022-02-17 22:34:30
-permalink: /pages/da3f07/
+permalink: /pages/cd38ec/
---
# JavaMail 快速入门
@@ -453,4 +453,4 @@ public static void main(String[] args) throws Exception {
ts.close();
System.out.println("message forwarded successfully....");
}
-```
+```
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/05.Jsoup.md" "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/05.Jsoup.md"
similarity index 99%
rename from "docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/05.Jsoup.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/05.Jsoup.md"
index 7c44697f..04f0cbd5 100644
--- "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/05.Jsoup.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/05.Jsoup.md"
@@ -1,16 +1,16 @@
---
title: Jsoup 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 05
+categories:
- Java
- 工具
-tags:
+ - 其他
+tags:
- Java
- Html
- Jsoup
-abbrlink: 2dece711
-date: 2022-02-17 22:34:30
-permalink: /pages/c516cc/
+permalink: /pages/5dd78d/
---
# Jsoup 快速入门
@@ -447,4 +447,4 @@ jsoup 提供了一系列的 `Whitelist` 基本配置,能够满足大多数要
- [jsoup github 托管代码](https://github.com/jhy/jsoup)
- [jsoup Cookbook](https://jsoup.org/cookbook/)
- [jsoup Cookbook(中文版)](http://www.open-open.com/jsoup/)
-- [不错的 jsoup 学习笔记](https://github.com/code4craft/jsoup-learning)
+- [不错的 jsoup 学习笔记](https://github.com/code4craft/jsoup-learning)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/06.Thumbnailator.md" "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/06.Thumbnailator.md"
similarity index 98%
rename from "docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/06.Thumbnailator.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/06.Thumbnailator.md"
index f6841876..71151154 100644
--- "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/06.Thumbnailator.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/06.Thumbnailator.md"
@@ -1,16 +1,16 @@
---
title: Thumbnailator 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 06
+categories:
- Java
- 工具
-tags:
+ - 其他
+tags:
- Java
- 图形处理
- Thumbnailator
-abbrlink: 950b94a1
-date: 2022-02-17 22:34:30
-permalink: /pages/aa9f61/
+permalink: /pages/adacc5/
---
# Thumbnailator 快速入门
@@ -239,4 +239,4 @@ Thumbnails.of("oldFile.png", "oldFile2.png")
## 参考
-[Thumbnailator 官方示例文档](https://github.com/coobird/thumbnailator/wiki/Examples)
+[Thumbnailator 官方示例文档](https://github.com/coobird/thumbnailator/wiki/Examples)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/07.Zxing.md" "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/07.Zxing.md"
similarity index 96%
rename from "docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/07.Zxing.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/07.Zxing.md"
index 0e6b2fd0..d5f691bb 100644
--- "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/07.Zxing.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/07.Zxing.md"
@@ -1,16 +1,16 @@
---
title: ZXing 快速入门
-categories:
- - 编程
+date: 2022-02-17 22:34:30
+order: 07
+categories:
- Java
- 工具
-tags:
+ - 其他
+tags:
- Java
- 条形码
- ZXing
-abbrlink: b465c57d
-date: 2022-02-17 22:34:30
-permalink: /pages/cc8ce5/
+permalink: /pages/b563af/
---
# ZXing 快速入门
@@ -94,4 +94,4 @@ public String decode(String filepath) throws IOException, NotFoundException {
## 参考
-[ZXing github 仓库](https://github.com/zxing/zxing)
+[ZXing github 仓库](https://github.com/zxing/zxing)
\ No newline at end of file
diff --git "a/docs/12.\345\267\245\345\205\267/README.md" "b/docs/01.Java/12.\345\267\245\345\205\267/README.md"
similarity index 87%
rename from "docs/12.\345\267\245\345\205\267/README.md"
rename to "docs/01.Java/12.\345\267\245\345\205\267/README.md"
index cd9949f6..dbd1c924 100644
--- "a/docs/12.\345\267\245\345\205\267/README.md"
+++ "b/docs/01.Java/12.\345\267\245\345\205\267/README.md"
@@ -1,16 +1,15 @@
---
title: Java 工具
-categories:
- - 编程
+date: 2022-02-18 08:53:11
+categories:
- Java
- 工具
-tags:
+tags:
- Java
- 工具
-abbrlink: 13035347
-date: 2022-02-18 08:53:11
+permalink: /pages/1123e1/
hidden: true
-permalink: /pages/4b6820/
+index: false
---
# Java 工具
@@ -54,4 +53,4 @@ permalink: /pages/4b6820/
## 🚪 传送
-◾ 🏠 [JAVA-TUTORIAL 首页](https://github.com/dunwu/java-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾
\ No newline at end of file
diff --git "a/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/01.Spring\346\246\202\350\277\260.md" "b/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/01.Spring\346\246\202\350\277\260.md"
new file mode 100644
index 00000000..3a202241
--- /dev/null
+++ "b/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/01.Spring\346\246\202\350\277\260.md"
@@ -0,0 +1,188 @@
+---
+title: Spring Framework 综述
+date: 2019-11-22 10:46:02
+order: 01
+categories:
+ - Java
+ - 框架
+ - Spring
+ - Spring综合
+tags:
+ - Java
+ - 框架
+ - Spring
+permalink: /pages/9d3091/
+---
+
+# Spring Framework 综述
+
+## Spring Framework 简介
+
+Spring Framework 是最受欢迎的企业级 Java 应用程序开发框架。用于构建企业级应用的轻量级、一站式解决方案。
+
+当谈论到大小和透明度时, Spring 是轻量级的。 Spring 框架的基础版本是在 2 MB 左右的。
+
+Spring 框架的核心特性可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。
+
+Spring Framework 设计理念如下:
+
+- 力争让选择无处不在
+- 体现海纳百川的精神
+- 保持后向兼容性
+- 专注 API 设计
+- 追求严苛的代码质量
+
+## 为什么使用 Spring
+
+下面列出的是使用 Spring 框架主要的好处:
+
+- Spring 可以使开发人员使用 POJOs 开发企业级的应用程序。只使用 POJOs 的好处是你不需要一个 EJB 容器产品,比如一个应用程序服务器,但是你可以选择使用一个健壮的 servlet 容器,比如 Tomcat 或者一些商业产品。
+- Spring 在一个单元模式中是有组织的。即使包和类的数量非常大,你只需要选择你需要的部分,而忽略剩余的那部分。
+- Spring 不会让你白费力气做重复工作,它真正的利用了一些现有的技术,像几个 ORM 框架、日志框架、JEE、Quartz 和 JDK 计时器,其他视图技术。
+- 测试一个用 Spring 编写的应用程序很容易,因为 environment-dependent 代码被放进了这个框架中。此外,通过使用 JavaBean-style POJOs,它在使用依赖注入注入测试数据时变得更容易。
+- Spring 的 web 框架是一个设计良好的 web MVC 框架,它为 web 框架,比如 Structs 或者其他工程上的或者很少受欢迎的 web 框架,提供了一个很好的供替代的选择。
+- 为将特定技术的异常(例如,由 JDBC、Hibernate,或者 JDO 抛出的异常)翻译成一致的, Spring 提供了一个方便的 API,而这些都是未经检验的异常。
+- 轻量级的 IOC 容器往往是轻量级的,例如,特别是当与 EJB 容器相比的时候。这有利于在内存和 CPU 资源有限的计算机上开发和部署应用程序。
+- Spring 提供了一个一致的事务管理界面,该界面可以缩小成一个本地事务(例如,使用一个单一的数据库)和扩展成一个全局事务(例如,使用 JTA)。
+
+## 核心思想
+
+Spring 最核心的两个技术思想是:IoC 和 Aop
+
+### IoC
+
+`IoC` 即 `Inversion of Control` ,意为控制反转。
+
+Spring 最认同的技术是控制反转的**依赖注入(DI)**模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。
+
+当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。
+
+到底什么是依赖注入?让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。所有这一切都意味着类 B 将通过 IoC 被注入到类 A 中。
+
+依赖注入可以以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。由于依赖注入是 Spring 框架的核心部分,所以我将在一个单独的章节中利用很好的例子去解释这一概念。
+
+### Aop
+
+Spring 框架的一个关键组件是**面向方面的程序设计(AOP)**框架。一个程序中跨越多个点的功能被称为**横切关注点**,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。
+
+在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。
+
+Spring 框架的 AOP 模块提供了面向方面的程序设计实现,允许你定义拦截器方法和切入点,可以实现将应该被分开的代码干净的分开功能。我将在一个独立的章节中讨论更多关于 Spring AOP 的概念。
+
+## Spring 体系结构
+
+Spring 当前框架有**20**个 jar 包,大致可以分为**6**大模块:
+
+- 1. 为什么使用 Spring
+- 2. 核心思想
+ - 2.1. IoC
+ - 2.2. Aop
+- 3. Spring 体系结构
+ - 3.1. Core Container
+ - 3.1.1. BeanFactory
+ - 3.1.2. ApplicationContext
+ - 3.2. AOP and Instrumentation
+ - 3.3. Messaging
+ - 3.4. Data Access / Integaration
+ - 3.5. Web
+ - 3.6. Test
+- 4. 术语
+
+Spring 框架提供了非常丰富的功能,因此整个架构也很庞大。
+在我们实际的应用开发中,并不一定要使用所有的功能,而是可以根据需要选择合适的 Spring 模块。
+
+
+
+### Core Container
+
+IoC 容器是 Spring 框架的核心。spring 容器使用依赖注入管理构成应用的组件,它会创建相互协作的组件之间的关联。毫无疑问,这些对象更简单干净,更容易理解,也更容易重用和测试。
+Spring 自带了几种容器的实现,可归纳为两种类型:
+
+#### BeanFactory
+
+由 org.springframework.beans.factory.BeanFactory 接口定义。
+它是最简单的容器,提供基本的 DI 支持。
+
+#### ApplicationContext
+
+由 org.springframework.context.ApplicationContext 接口定义。
+它是基于 BeanFactory 之上构建,并提供面向应用的服务,例如从属性文件解析文本信息的能力,以及发布应用事件给感兴趣的事件监听者的能力。
+**_注:Bean 工厂对于大多数应用来说往往太低级了,所以应用上下文使用更广泛。推荐在开发中使用应用上下文容器。_**
+
+Spring 自带了多种应用上下文,最可能遇到的有以下几种:
+`ClassPathXmlApplicationContext`:从类路径下的 XML 配置文件中加载上下文定义,把应用上下文定义文件当做类资源。
+`FileSystemXmlApplicationContext`:读取文件系统下的 XML 配置文件并加载上下文定义。
+`XmlWebApplicationContext`:读取 Web 应用下的 XML 配置文件并装载上下文定义。
+
+**_范例_**
+
+```java
+ApplicationContext context = new FileSystemXmlApplicationContext("D:\Temp\build.xml");
+ApplicationContext context2 = new ClassPathXmlApplicationContext("build.xml");
+```
+
+可以看到,加载 `FileSystemXmlApplicationContext` 和 `ClassPathXmlApplicationContext` 十分相似。
+差异在于:前者在指定文件系统路径下查找 build.xml 文件;而后在所有类路径(包含 JAR 文件)下查找 build.xml 文件。
+通过引用应用上下文,可以很方便的调用 getBean() 方法从 Spring 容器中获取 Bean。
+
+**相关 jar 包**
+
+- `spring-core`, `spring-beans`, 提供框架的基础部分,包括 IoC 和依赖注入特性。
+
+- `spring-context`, 在`spring-core`, `spring-beans`基础上构建。它提供一种框架式的访问对象的方法。它也支持类似 Java EE 特性,例如:EJB,JMX 和基本 remoting。ApplicationContext 接口是它的聚焦点。
+- `springcontext-support`, 集成第三方库到 Spring application context。
+- `spring-expression`,提供一种强有力的表达语言在运行时来查询和操纵一个对象图。
+
+### AOP and Instrumentation
+
+**相关 jar 包**
+
+- `spring-aop`,提供了对面向切面编程的丰富支持。
+- `spring-aspects`,提供了对 AspectJ 的集成。
+- `spring-instrument`,提供了对类 instrumentation 的支持和类加载器。
+- `spring-instrument-tomcat`,包含了 Spring 对 Tomcat 的 instrumentation 代理。
+
+### Messaging
+
+**相关 jar 包**
+
+- `spring-messaging`,包含 spring 的消息处理功能,如 Message,MessageChannel,MessageHandler。
+
+### Data Access / Integaration
+
+Data Access/Integration 层包含了 JDBC / ORM / OXM / JMS 和 Transaction 模块。
+
+**相关 jar 包**
+
+- `spring-jdbc`,提供了一个 JDBC 抽象层。
+
+- `spring-tx`,支持编程和声明式事务管理类。
+- `spring-orm`,提供了流行的对象关系型映射 API 集,如 JPA,JDO,Hibernate。
+- `spring-oxm`,提供了一个抽象层以支持对象/XML 映射的实现,如 JAXB,Castor,XMLBeans,JiBX 和 XStream.
+- `spring-jms`,包含了生产和消费消息的功能。
+
+### Web
+
+**相关 jar 包**
+
+- `spring-web`,提供了基本的面向 web 的功能,如多文件上传、使用 Servlet 监听器的 Ioc 容器的初始化。一个面向 web 的应用层上下文。
+
+- `spring-webmvc`,包括 MVC 和 REST web 服务实现。
+- `spring-webmvc-portlet`,提供在 Protlet 环境的 MVC 实现和`spring-webmvc`功能的镜像。
+
+### Test
+
+**相关 jar 包**
+
+- `spring-test`,以 Junit 和 TestNG 来支持 spring 组件的单元测试和集成测试。
+
+## 术语
+
+- **应用程序**:是能完成我们所需要功能的成品,比如购物网站、OA 系统。
+- **框架**:是能完成一定功能的半成品,比如我们可以使用框架进行购物网站开发;框架做一部分功能,我们自己做一部分功能,这样应用程序就创建出来了。而且框架规定了你在开发应用程序时的整体架构,提供了一些基础功能,还规定了类和对象的如何创建、如何协作等,从而简化我们开发,让我们专注于业务逻辑开发。
+- **非侵入式设计**:从框架角度可以这样理解,无需继承框架提供的类,这种设计就可以看作是非侵入式设计,如果继承了这些框架类,就是侵入设计,如果以后想更换框架之前写过的代码几乎无法重用,如果非侵入式设计则之前写过的代码仍然可以继续使用。
+- **轻量级及重量级**:轻量级是相对于重量级而言的,轻量级一般就是非入侵性的、所依赖的东西非常少、资源占用非常少、部署简单等等,其实就是比较容易使用,而重量级正好相反。
+- **POJO**:POJO(Plain Old Java Objects)简单的 Java 对象,它可以包含业务逻辑或持久化逻辑,但不担当任何特殊角色且不继承或不实现任何其它 Java 框架的类或接口。
+- **容器**:在日常生活中容器就是一种盛放东西的器具,从程序设计角度看就是装对象的的对象,因为存在放入、拿出等操作,所以容器还要管理对象的生命周期。
+- **控制反转:**即 Inversion of Control,缩写为 IoC,控制反转还有一个名字叫做依赖注入(Dependency Injection),就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。
+- **JavaBean**:一般指容器管理对象,在 Spring 中指 Spring IoC 容器管理对象。
\ No newline at end of file
diff --git "a/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/21.SpringBoot\347\237\245\350\257\206\345\233\276\350\260\261.md" "b/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/21.SpringBoot\347\237\245\350\257\206\345\233\276\350\260\261.md"
new file mode 100644
index 00000000..3a5733b4
--- /dev/null
+++ "b/docs/01.Java/13.\346\241\206\346\236\266/01.Spring/00.Spring\347\273\274\345\220\210/21.SpringBoot\347\237\245\350\257\206\345\233\276\350\260\261.md"
@@ -0,0 +1,951 @@
+---
+title: SpringBoot 知识图谱
+date: 2020-08-12 07:01:26
+order: 21
+categories:
+ - Java
+ - 框架
+ - Spring
+ - Spring综合
+tags:
+ - Java
+ - 框架
+ - Spring
+ - SpringBoot
+permalink: /pages/430f53/
+---
+
+# SpringBoot 知识图谱
+
+> 1. 预警:本文非常长,建议先 mark 后看,也许是最后一次写这么长的文章
+> 2. 说明:前面有 4 个小节关于 Spring 的基础知识,分别是:IOC 容器、JavaConfig、事件监听、SpringFactoriesLoader 详解,它们占据了本文的大部分内容,虽然它们之间可能没有太多的联系,但这些知识对于理解 Spring Boot 的核心原理至关重要,如果你对 Spring 框架烂熟于心,完全可以跳过这 4 个小节。正是因为这个系列的文章是由这些看似不相关的知识点组成,因此取名知识清单。
+
+在过去两三年的 Spring 生态圈,最让人兴奋的莫过于 Spring Boot 框架。或许从命名上就能看出这个框架的设计初衷:快速的启动 Spring 应用。因而 Spring Boot 应用本质上就是一个基于 Spring 框架的应用,它是 Spring 对“约定优先于配置”理念的最佳实践产物,它能够帮助开发者更快速高效地构建基于 Spring 生态圈的应用。
+
+那 Spring Boot 有何魔法?**自动配置**、**起步依赖**、**Actuator**、**命令行界面(CLI)** 是 Spring Boot 最重要的 4 大核心特性,其中 CLI 是 Spring Boot 的可选特性,虽然它功能强大,但也引入了一套不太常规的开发模型,因而这个系列的文章仅关注其它 3 种特性。如文章标题,本文是这个系列的第一部分,将为你打开 Spring Boot 的大门,重点为你剖析其启动流程以及自动配置实现原理。要掌握这部分核心内容,理解一些 Spring 框架的基础知识,将会让你事半功倍。
+
+## 一、抛砖引玉:探索 Spring IoC 容器
+
+如果有看过`SpringApplication.run()`方法的源码,Spring Boot 冗长无比的启动流程一定会让你抓狂,透过现象看本质,SpringApplication 只是将一个典型的 Spring 应用的启动流程进行了扩展,因此,透彻理解 Spring 容器是打开 Spring Boot 大门的一把钥匙。
+
+### 1.1、Spring IoC 容器
+
+可以把 Spring IoC 容器比作一间餐馆,当你来到餐馆,通常会直接招呼服务员:点菜!至于菜的原料是什么?如何用原料把菜做出来?可能你根本就不关心。IoC 容器也是一样,你只需要告诉它需要某个 bean,它就把对应的实例(instance)扔给你,至于这个 bean 是否依赖其他组件,怎样完成它的初始化,根本就不需要你关心。
+
+作为餐馆,想要做出菜肴,得知道菜的原料和菜谱,同样地,IoC 容器想要管理各个业务对象以及它们之间的依赖关系,需要通过某种途径来记录和管理这些信息。`BeanDefinition`对象就承担了这个责任:容器中的每一个 bean 都会有一个对应的 BeanDefinition 实例,该实例负责保存 bean 对象的所有必要信息,包括 bean 对象的 class 类型、是否是抽象类、构造方法和参数、其它属性等等。当客户端向容器请求相应对象时,容器就会通过这些信息为客户端返回一个完整可用的 bean 实例。
+
+原材料已经准备好(把 BeanDefinition 看着原料),开始做菜吧,等等,你还需要一份菜谱,`BeanDefinitionRegistry`和`BeanFactory`就是这份菜谱,BeanDefinitionRegistry 抽象出 bean 的注册逻辑,而 BeanFactory 则抽象出了 bean 的管理逻辑,而各个 BeanFactory 的实现类就具体承担了 bean 的注册以及管理工作。它们之间的关系就如下图:
+
+ _BeanFactory、BeanDefinitionRegistry 关系图(来自:Spring 揭秘)_
+
+`DefaultListableBeanFactory`作为一个比较通用的 BeanFactory 实现,它同时也实现了 BeanDefinitionRegistry 接口,因此它就承担了 Bean 的注册管理工作。从图中也可以看出,BeanFactory 接口中主要包含 getBean、containBean、getType、getAliases 等管理 bean 的方法,而 BeanDefinitionRegistry 接口则包含 registerBeanDefinition、removeBeanDefinition、getBeanDefinition 等注册管理 BeanDefinition 的方法。
+
+下面通过一段简单的代码来模拟 BeanFactory 底层是如何工作的:
+
+```
+// 默认容器实现
+DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
+// 根据业务对象构造相应的BeanDefinition
+AbstractBeanDefinition definition = new RootBeanDefinition(Business.class,true);
+// 将bean定义注册到容器中
+beanRegistry.registerBeanDefinition("beanName",definition);
+// 如果有多个bean,还可以指定各个bean之间的依赖关系
+// ........
+
+// 然后可以从容器中获取这个bean的实例
+// 注意:这里的beanRegistry其实实现了BeanFactory接口,所以可以强转,
+// 单纯的BeanDefinitionRegistry是无法强制转换到BeanFactory类型的
+BeanFactory container = (BeanFactory)beanRegistry;
+Business business = (Business)container.getBean("beanName");
+```
+
+这段代码仅为了说明 BeanFactory 底层的大致工作流程,实际情况会更加复杂,比如 bean 之间的依赖关系可能定义在外部配置文件(XML/Properties)中、也可能是注解方式。Spring IoC 容器的整个工作流程大致可以分为两个阶段:
+
+①、容器启动阶段
+
+容器启动时,会通过某种途径加载`Configuration MetaData`。除了代码方式比较直接外,在大部分情况下,容器需要依赖某些工具类,比如:`BeanDefinitionReader`,BeanDefinitionReader 会对加载的`Configuration MetaData`进行解析和分析,并将分析后的信息组装为相应的 BeanDefinition,最后把这些保存了 bean 定义的 BeanDefinition,注册到相应的 BeanDefinitionRegistry,这样容器的启动工作就完成了。这个阶段主要完成一些准备性工作,更侧重于 bean 对象管理信息的收集,当然一些验证性或者辅助性的工作也在这一阶段完成。
+
+来看一个简单的例子吧,过往,所有的 bean 都定义在 XML 配置文件中,下面的代码将模拟 BeanFactory 如何从配置文件中加载 bean 的定义以及依赖关系:
+
+```
+// 通常为BeanDefinitionRegistry的实现类,这里以DeFaultListabeBeanFactory为例
+BeanDefinitionRegistry beanRegistry = new DefaultListableBeanFactory();
+// XmlBeanDefinitionReader实现了BeanDefinitionReader接口,用于解析XML文件
+XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReaderImpl(beanRegistry);
+// 加载配置文件
+beanDefinitionReader.loadBeanDefinitions("classpath:spring-bean.xml");
+
+// 从容器中获取bean实例
+BeanFactory container = (BeanFactory)beanRegistry;
+Business business = (Business)container.getBean("beanName");
+```
+
+②、Bean 的实例化阶段
+
+经过第一阶段,所有 bean 定义都通过 BeanDefinition 的方式注册到 BeanDefinitionRegistry 中,当某个请求通过容器的 getBean 方法请求某个对象,或者因为依赖关系容器需要隐式的调用 getBean 时,就会触发第二阶段的活动:容器会首先检查所请求的对象之前是否已经实例化完成。如果没有,则会根据注册的 BeanDefinition 所提供的信息实例化被请求对象,并为其注入依赖。当该对象装配完毕后,容器会立即将其返回给请求方法使用。
+
+BeanFactory 只是 Spring IoC 容器的一种实现,如果没有特殊指定,它采用采用延迟初始化策略:只有当访问容器中的某个对象时,才对该对象进行初始化和依赖注入操作。而在实际场景下,我们更多的使用另外一种类型的容器:`ApplicationContext`,它构建在 BeanFactory 之上,属于更高级的容器,除了具有 BeanFactory 的所有能力之外,还提供对事件监听机制以及国际化的支持等。它管理的 bean,在容器启动时全部完成初始化和依赖注入操作。
+
+### 1.2、Spring 容器扩展机制
+
+IoC 容器负责管理容器中所有 bean 的生命周期,而在 bean 生命周期的不同阶段,Spring 提供了不同的扩展点来改变 bean 的命运。在容器的启动阶段,`BeanFactoryPostProcessor`允许我们在容器实例化相应对象之前,对注册到容器的 BeanDefinition 所保存的信息做一些额外的操作,比如修改 bean 定义的某些属性或者增加其他信息等。
+
+如果要自定义扩展类,通常需要实现`org.springframework.beans.factory.config.BeanFactoryPostProcessor`接口,与此同时,因为容器中可能有多个 BeanFactoryPostProcessor,可能还需要实现`org.springframework.core.Ordered`接口,以保证 BeanFactoryPostProcessor 按照顺序执行。Spring 提供了为数不多的 BeanFactoryPostProcessor 实现,我们以`PropertyPlaceholderConfigurer`来说明其大致的工作流程。
+
+在 Spring 项目的 XML 配置文件中,经常可以看到许多配置项的值使用占位符,而将占位符所代表的值单独配置到独立的 properties 文件,这样可以将散落在不同 XML 文件中的配置集中管理,而且也方便运维根据不同的环境进行配置不同的值。这个非常实用的功能就是由 PropertyPlaceholderConfigurer 负责实现的。
+
+根据前文,当 BeanFactory 在第一阶段加载完所有配置信息时,BeanFactory 中保存的对象的属性还是以占位符方式存在的,比如`${jdbc.mysql.url}`。当 PropertyPlaceholderConfigurer 作为 BeanFactoryPostProcessor 被应用时,它会使用 properties 配置文件中的值来替换相应的 BeanDefinition 中占位符所表示的属性值。当需要实例化 bean 时,bean 定义中的属性值就已经被替换成我们配置的值。当然其实现比上面描述的要复杂一些,这里仅说明其大致工作原理,更详细的实现可以参考其源码。
+
+与之相似的,还有`BeanPostProcessor`,其存在于对象实例化阶段。跟 BeanFactoryPostProcessor 类似,它会处理容器内所有符合条件并且已经实例化后的对象。简单的对比,BeanFactoryPostProcessor 处理 bean 的定义,而 BeanPostProcessor 则处理 bean 完成实例化后的对象。BeanPostProcessor 定义了两个接口:
+
+```
+public interface BeanPostProcessor {
+ // 前置处理
+ Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
+ // 后置处理
+ Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
+}
+```
+
+为了理解这两个方法执行的时机,简单的了解下 bean 的整个生命周期:
+
+`postProcessBeforeInitialization()`方法与`postProcessAfterInitialization()`分别对应图中前置处理和后置处理两个步骤将执行的方法。这两个方法中都传入了 bean 对象实例的引用,为扩展容器的对象实例化过程提供了很大便利,在这儿几乎可以对传入的实例执行任何操作。注解、AOP 等功能的实现均大量使用了`BeanPostProcessor`,比如有一个自定义注解,你完全可以实现 BeanPostProcessor 的接口,在其中判断 bean 对象的脑袋上是否有该注解,如果有,你可以对这个 bean 实例执行任何操作,想想是不是非常的简单?
+
+再来看一个更常见的例子,在 Spring 中经常能够看到各种各样的 Aware 接口,其作用就是在对象实例化完成以后将 Aware 接口定义中规定的依赖注入到当前实例中。比如最常见的`ApplicationContextAware`接口,实现了这个接口的类都可以获取到一个 ApplicationContext 对象。当容器中每个对象的实例化过程走到 BeanPostProcessor 前置处理这一步时,容器会检测到之前注册到容器的 ApplicationContextAwareProcessor,然后就会调用其 postProcessBeforeInitialization()方法,检查并设置 Aware 相关依赖。看看代码吧,是不是很简单:
+
+```
+// 代码来自:org.springframework.context.support.ApplicationContextAwareProcessor
+// 其postProcessBeforeInitialization方法调用了invokeAwareInterfaces方法
+private void invokeAwareInterfaces(Object bean) {
+ if (bean instanceof EnvironmentAware) {
+ ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
+ }
+ if (bean instanceof ApplicationContextAware) {
+ ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
+ }
+ // ......
+}
+```
+
+最后总结一下,本小节内容和你一起回顾了 Spring 容器的部分核心内容,限于篇幅不能写更多,但理解这部分内容,足以让您轻松理解 Spring Boot 的启动原理,如果在后续的学习过程中遇到一些晦涩难懂的知识,再回过头来看看 Spring 的核心知识,也许有意想不到的效果。也许 Spring Boot 的中文资料很少,但 Spring 的中文资料和书籍有太多太多,总有东西能给你启发。
+
+## 二、夯实基础:JavaConfig 与常见 Annotation
+
+### 2.1、JavaConfig
+
+我们知道`bean`是 Spring IOC 中非常核心的概念,Spring 容器负责 bean 的生命周期的管理。在最初,Spring 使用 XML 配置文件的方式来描述 bean 的定义以及相互间的依赖关系,但随着 Spring 的发展,越来越多的人对这种方式表示不满,因为 Spring 项目的所有业务类均以 bean 的形式配置在 XML 文件中,造成了大量的 XML 文件,使项目变得复杂且难以管理。
+
+后来,基于纯 Java Annotation 依赖注入框架`Guice`出世,其性能明显优于采用 XML 方式的 Spring,甚至有部分人认为,`Guice`可以完全取代 Spring(`Guice`仅是一个轻量级 IOC 框架,取代 Spring 还差的挺远)。正是这样的危机感,促使 Spring 及社区推出并持续完善了`JavaConfig`子项目,它基于 Java 代码和 Annotation 注解来描述 bean 之间的依赖绑定关系。比如,下面是使用 XML 配置方式来描述 bean 的定义:
+
+```
+
+```
+
+而基于 JavaConfig 的配置形式是这样的:
+
+```
+@Configuration
+public class MoonBookConfiguration {
+
+ // 任何标志了@Bean的方法,其返回值将作为一个bean注册到Spring的IOC容器中
+ // 方法名默认成为该bean定义的id
+ @Bean
+ public BookService bookService() {
+ return new BookServiceImpl();
+ }
+}
+```
+
+如果两个 bean 之间有依赖关系的话,在 XML 配置中应该是这样:
+
+```
+
+
+
+
+
+
+
+
+
+```
+
+而在 JavaConfig 中则是这样:
+
+```
+@Configuration
+public class MoonBookConfiguration {
+
+ // 如果一个bean依赖另一个bean,则直接调用对应JavaConfig类中依赖bean的创建方法即可
+ // 这里直接调用dependencyService()
+ @Bean
+ public BookService bookService() {
+ return new BookServiceImpl(dependencyService());
+ }
+
+ @Bean
+ public OtherService otherService() {
+ return new OtherServiceImpl(dependencyService());
+ }
+
+ @Bean
+ public DependencyService dependencyService() {
+ return new DependencyServiceImpl();
+ }
+}
+```
+
+你可能注意到这个示例中,有两个 bean 都依赖于 dependencyService,也就是说当初始化 bookService 时会调用`dependencyService()`,在初始化 otherService 时也会调用`dependencyService()`,那么问题来了?这时候 IOC 容器中是有一个 dependencyService 实例还是两个?这个问题留着大家思考吧,这里不再赘述。
+
+### 2.2、@ComponentScan
+
+`@ComponentScan`注解对应 XML 配置形式中的``元素,表示启用组件扫描,Spring 会自动扫描所有通过注解配置的 bean,然后将其注册到 IOC 容器中。我们可以通过`basePackages`等属性来指定`@ComponentScan`自动扫描的范围,如果不指定,默认从声明`@ComponentScan`所在类的`package`进行扫描。正因为如此,SpringBoot 的启动类都默认在`src/main/java`下。
+
+### 2.3、@Import
+
+`@Import`注解用于导入配置类,举个简单的例子:
+
+```
+@Configuration
+public class MoonBookConfiguration {
+ @Bean
+ public BookService bookService() {
+ return new BookServiceImpl();
+ }
+}
+```
+
+现在有另外一个配置类,比如:`MoonUserConfiguration`,这个配置类中有一个 bean 依赖于`MoonBookConfiguration`中的 bookService,如何将这两个 bean 组合在一起?借助`@Import`即可:
+
+```
+@Configuration
+// 可以同时导入多个配置类,比如:@Import({A.class,B.class})
+@Import(MoonBookConfiguration.class)
+public class MoonUserConfiguration {
+ @Bean
+ public UserService userService(BookService bookService) {
+ return new BookServiceImpl(bookService);
+ }
+}
+```
+
+需要注意的是,在 4.2 之前,`@Import`注解只支持导入配置类,但是在 4.2 之后,它支持导入普通类,并将这个类作为一个 bean 的定义注册到 IOC 容器中。
+
+### 2.4、@Conditional
+
+`@Conditional`注解表示在满足某种条件后才初始化一个 bean 或者启用某些配置。它一般用在由`@Component`、`@Service`、`@Configuration`等注解标识的类上面,或者由`@Bean`标记的方法上。如果一个`@Configuration`类标记了`@Conditional`,则该类中所有标识了`@Bean`的方法和`@Import`注解导入的相关类将遵从这些条件。
+
+在 Spring 里可以很方便的编写你自己的条件类,所要做的就是实现`Condition`接口,并覆盖它的`matches()`方法。举个例子,下面的简单条件类表示只有在`Classpath`里存在`JdbcTemplate`类时才生效:
+
+```
+public class JdbcTemplateCondition implements Condition {
+
+ @Override
+ public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
+ try {
+ conditionContext.getClassLoader().loadClass("org.springframework.jdbc.core.JdbcTemplate");
+ return true;
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+}
+```
+
+当你用 Java 来声明 bean 的时候,可以使用这个自定义条件类:
+
+```
+@Conditional(JdbcTemplateCondition.class)
+@Service
+public MyService service() {
+ ......
+}
+```
+
+这个例子中只有当`JdbcTemplateCondition`类的条件成立时才会创建 MyService 这个 bean。也就是说 MyService 这 bean 的创建条件是`classpath`里面包含`JdbcTemplate`,否则这个 bean 的声明就会被忽略掉。
+
+`Spring Boot`定义了很多有趣的条件,并把他们运用到了配置类上,这些配置类构成了`Spring Boot`的自动配置的基础。`Spring Boot`运用条件化配置的方法是:定义多个特殊的条件化注解,并将它们用到配置类上。下面列出了`Spring Boot`提供的部分条件化注解:
+
+| 条件化注解 | 配置生效条件 |
+| ------------------------------- | ------------------------------------------------------- |
+| @ConditionalOnBean | 配置了某个特定 bean |
+| @ConditionalOnMissingBean | 没有配置特定的 bean |
+| @ConditionalOnClass | Classpath 里有指定的类 |
+| @ConditionalOnMissingClass | Classpath 里没有指定的类 |
+| @ConditionalOnExpression | 给定的 Spring Expression Language 表达式计算结果为 true |
+| @ConditionalOnJava | Java 的版本匹配特定指或者一个范围值 |
+| @ConditionalOnProperty | 指定的配置属性要有一个明确的值 |
+| @ConditionalOnResource | Classpath 里有指定的资源 |
+| @ConditionalOnWebApplication | 这是一个 Web 应用程序 |
+| @ConditionalOnNotWebApplication | 这不是一个 Web 应用程序 |
+
+### 2.5、@ConfigurationProperties 与@EnableConfigurationProperties
+
+当某些属性的值需要配置的时候,我们一般会在`application.properties`文件中新建配置项,然后在 bean 中使用`@Value`注解来获取配置的值,比如下面配置数据源的代码。
+
+```
+// jdbc config
+jdbc.mysql.url=jdbc:mysql://localhost:3306/sampledb
+jdbc.mysql.username=root
+jdbc.mysql.password=123456
+......
+
+// 配置数据源
+@Configuration
+public class HikariDataSourceConfiguration {
+
+ @Value("jdbc.mysql.url")
+ public String url;
+ @Value("jdbc.mysql.username")
+ public String user;
+ @Value("jdbc.mysql.password")
+ public String password;
+
+ @Bean
+ public HikariDataSource dataSource() {
+ HikariConfig hikariConfig = new HikariConfig();
+ hikariConfig.setJdbcUrl(url);
+ hikariConfig.setUsername(user);
+ hikariConfig.setPassword(password);
+ // 省略部分代码
+ return new HikariDataSource(hikariConfig);
+ }
+}
+```
+
+使用`@Value`注解注入的属性通常都比较简单,如果同一个配置在多个地方使用,也存在不方便维护的问题(考虑下,如果有几十个地方在使用某个配置,而现在你想改下名字,你改怎么做?)。对于更为复杂的配置,Spring Boot 提供了更优雅的实现方式,那就是`@ConfigurationProperties`注解。我们可以通过下面的方式来改写上面的代码:
+
+```
+@Component
+// 还可以通过@PropertySource("classpath:jdbc.properties")来指定配置文件
+@ConfigurationProperties("jdbc.mysql")
+// 前缀=jdbc.mysql,会在配置文件中寻找jdbc.mysql.*的配置项
+pulic class JdbcConfig {
+ public String url;
+ public String username;
+ public String password;
+}
+
+@Configuration
+public class HikariDataSourceConfiguration {
+
+ @AutoWired
+ public JdbcConfig config;
+
+ @Bean
+ public HikariDataSource dataSource() {
+ HikariConfig hikariConfig = new HikariConfig();
+ hikariConfig.setJdbcUrl(config.url);
+ hikariConfig.setUsername(config.username);
+ hikariConfig.setPassword(config.password);
+ // 省略部分代码
+ return new HikariDataSource(hikariConfig);
+ }
+}
+```
+
+`@ConfigurationProperties`对于更为复杂的配置,处理起来也是得心应手,比如有如下配置文件:
+
+```
+#App
+app.menus[0].title=Home
+app.menus[0].name=Home
+app.menus[0].path=/
+app.menus[1].title=Login
+app.menus[1].name=Login
+app.menus[1].path=/login
+
+app.compiler.timeout=5
+app.compiler.output-folder=/temp/
+
+app.error=/error/
+```
+
+可以定义如下配置类来接收这些属性
+
+```
+@Component
+@ConfigurationProperties("app")
+public class AppProperties {
+
+ public String error;
+ public List