From 99ad0595cf95af46fc97169d22abecd394052f05 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 10 Jun 2020 03:13:11 +0000
Subject: [PATCH 001/184] Bump netty-all from 4.1.6.Final to 4.1.42.Final in
/Spring-Netty
Bumps [netty-all](https://github.com/netty/netty) from 4.1.6.Final to 4.1.42.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.1.6.Final...netty-4.1.42.Final)
Signed-off-by: dependabot[bot]
---
Spring-Netty/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Spring-Netty/pom.xml b/Spring-Netty/pom.xml
index 14ee73a..3cfc328 100644
--- a/Spring-Netty/pom.xml
+++ b/Spring-Netty/pom.xml
@@ -16,7 +16,7 @@
1.8
- 4.1.6.Final
+ 4.1.42.Final
From 489ba8af0625365a4d96fbadd798d4dddea833cd Mon Sep 17 00:00:00 2001
From: LuoHaiYang
Date: Mon, 10 Aug 2020 07:15:11 +0800
Subject: [PATCH 002/184] =?UTF-8?q?=E6=B7=BB=E5=8A=A0dubbo=E5=92=8CSpringS?=
=?UTF-8?q?ecurity=E6=BA=90=E7=A0=81=E5=AD=A6=E4=B9=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
...2\220\347\240\201\347\216\257\345\242\203" | 14 ++
...70\345\277\203\351\200\273\350\276\221.md" | 193 ++++++++++++++++++
3 files changed, 208 insertions(+), 1 deletion(-)
create mode 100644 "note/Dubbo/\346\267\261\345\205\245Dubbo\345\255\246\344\271\240\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \346\220\255\345\273\272Dubbo\346\272\220\347\240\201\347\216\257\345\242\203"
create mode 100644 "note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md"
diff --git a/README.md b/README.md
index e8c5cad..3917282 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ Tip:
# 目录
- 项目导入
- 将整个JavaSourceLearning导入IDEA中,然后选中项目pom.xml文件右键,open as maven project然后等待maven下载相应jar包即可。
+ 将整个JavaSourceCodeLearning导入IDEA中,然后选中项目pom.xml文件右键,open as maven project然后等待maven下载相应jar包即可。
- JDK源码学习
- JDK版本:1.8.0_77
diff --git "a/note/Dubbo/\346\267\261\345\205\245Dubbo\345\255\246\344\271\240\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \346\220\255\345\273\272Dubbo\346\272\220\347\240\201\347\216\257\345\242\203" "b/note/Dubbo/\346\267\261\345\205\245Dubbo\345\255\246\344\271\240\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \346\220\255\345\273\272Dubbo\346\272\220\347\240\201\347\216\257\345\242\203"
new file mode 100644
index 0000000..aa7be9d
--- /dev/null
+++ "b/note/Dubbo/\346\267\261\345\205\245Dubbo\345\255\246\344\271\240\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \346\220\255\345\273\272Dubbo\346\272\220\347\240\201\347\216\257\345\242\203"
@@ -0,0 +1,14 @@
+## 前言
+
+想要深入学习Dubbo,最好的方式就是阅读并调用Dubbo源码。接下来先来动手搭建一个Dubbo源码。
+
+## 正文
+
+### 1. 下载源码
+
+步骤:
+
+1. 先从dubbo源码官网github中fork一份到自己的github仓库中。
+2. 使用命令:git branch v2.7.7。 切换到分支2.7.7。
+
+未完待续...
diff --git "a/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md" "b/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md"
new file mode 100644
index 0000000..94a450b
--- /dev/null
+++ "b/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md"
@@ -0,0 +1,193 @@
+@[toc]
+## 前言
+相信了解过SpringSecurity或者是OAuth2的读者,会发现网上会有非常多的相关文章,或是纯概念的,或是带有demo的,无论是哪种类型的文章,本人去阅读之后,对于整个框架的概念还是一知半解,也仅仅是实现了某些功能、某些效果而已,若遇到某些问题时无从下手,只能去百度去Google。这是因为对于SpringSecurity和OAuth2的知识没有一个整体概念的把握,知识体系没有形成系统,遂决定写一个关于SpringSecurity和OAuth2的系列专栏,在建造自己知识体系的同时还希望能帮助有同样困惑的同学。
+
+============== 分割线 ==============
+
+上一章已经讲解到了SpringSecurity用到了建造者模式来建造FilterChainProxy。本片就来详细分析下WebSecurity的核心逻辑以及AbstractConfiguredSecurityBuilder的doBuild()方法。
+
+## 正文
+
+### 1. AbstractConfiguredSecurityBuilder中安全配置类
+SpringSecurity通过SecurityConfigurer来构建FilterChainProxy,构建前还需要进行配置。因此AbstractConfiguredSecurityBuilder还需要注入配置组件SecurityConfigurer,初始化配置组件SecurityConfigurer,调用SecurityConfigurer的configure方法。
+
+在AbstractConfiguredSecurityBuilder类中,看下安全配置类的定义:‘
+
+```
+private final LinkedHashMap>, List>> configurers = new LinkedHashMap>, List>>();
+```
+这是定义的安全配置器的子类Map集合,这个configurers就是用于初始化以及配置FilterChainProxy中的filters用的。Map集合中,Key是SecurityConfigurer的子类的Class类型,Value是SecurityConfigurer的list集合。
+
+作为一个成员变量,自然会有方法从外部注入安全配置类。在AbstractConfiguredSecurityBuilder的类中,定义了add方法。
+
+```
+ private > void add(C configurer) throws Exception {
+ Assert.notNull(configurer, "configurer cannot be null");
+ // 获取安全配置类的Class类型
+ Class extends SecurityConfigurer> clazz = (Class extends SecurityConfigurer>) configurer
+ .getClass();
+ // 同步去操作安全配置类集合
+ synchronized (configurers) {
+ // 查看构建状态是否是已经配置
+ if (buildState.isConfigured()) {
+ throw new IllegalStateException("Cannot apply " + configurer
+ + " to already built object");
+ }
+ // 如果allowConfigurersOfSameType为true,则从configurers集合中获取clazz类型的安全配置类集合
+ List> configs = allowConfigurersOfSameType ? this.configurers
+ .get(clazz) : null;
+ if (configs == null) {
+ // 初始化安全配置类结合
+ configs = new ArrayList>(1);
+ }
+ // 将安全配置类添加至configs的list集合中
+ configs.add(configurer);
+ // 以clazz为key,configs为value存入configurers的LinkedHashMap集合中
+ this.configurers.put(clazz, configs);
+ if (buildState.isInitializing()) {
+ this.configurersAddedInInitializing.add(configurer);
+ }
+ }
+ }
+
+```
+
+通过IDEA来查看下哪些地方调用了add方法
+
+
+看下apply方法
+```
+ // 传入的C是SecurityConfigurerAdapter的子类,
+ public > C apply(C configurer)
+ throws Exception {
+ // 传入objectPostProcessor,该对象用于创建各种“实例”,具体什么作用下问会讲解,请留意
+ configurer.addObjectPostProcessor(objectPostProcessor);
+ // 将当前对象设置为构建者
+ configurer.setBuilder((B) this);
+ // 调用add方法,向configurers集合中添加configurer
+ add(configurer);
+ return configurer;
+ }
+
+```
+
+继续查看apply方法有哪些地方调用了的
+
+图上的HttpSecurity的getOrApply方法值得注意一下,查看其方法
+```
+ private > C getOrApply(
+ C configurer) throws Exception {
+ // 从configurers集合中获取安全配置类
+ C existingConfig = (C) getConfigurer(configurer.getClass());
+ if (existingConfig != null) {
+ // 如果存在则直接返回该安全配置类
+ return existingConfig;
+ }
+ // 如果不存在则调用apply方法去应用该安全配置类,并缓存到configurers集合中
+ return apply(configurer);
+ }
+
+```
+
+getOrApply方法主要是从configurers集合中获取配置类,如果存在则直接返回,否则则应用该配置类。
+
+继续查看getOrApply有哪些地方在调用。这下终于看到了安全配置类了。
+
+
+这里有一个问题值得思考,这些配置类到底是干嘛用的?这里就以ExpressionUrlAuthorizationConfigurer配置类为例,看下其类内部configure方法逻辑。
+
+找了一圈,发现configure的实现是在ExpressionUrlAuthorizationConfigurer的抽象父类AbstractInterceptUrlConfigurer定义的。
+
+```
+ @Override
+ public void configure(H http) throws Exception {
+ // 创建元数据,该抽象方法由ExpressionUrlAuthorizationConfigurer定义,返回一个ExpressionBasedFilterInvocationSecurityMetadataSource对象
+ FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);
+ // 如果配置失败,则数据源配置失败
+ if (metadataSource == null) {
+ return;
+ }
+ // 创建一个FilterSecurityInterceptor对象
+ FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(
+ http, metadataSource, http.getSharedObject(AuthenticationManager.class));
+ if (filterSecurityInterceptorOncePerRequest != null) {
+ securityInterceptor
+ .setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
+ }
+ // 通过objectPostProcessor创建一个securityInterceptor实例对象
+ securityInterceptor = postProcess(securityInterceptor);
+ http.addFilter(securityInterceptor);
+ // 将实例对象存入SharedObject缓存中
+ http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
+ }
+
+```
+
+从ExpressionUrlAuthorizationConfigurer的抽象父类AbstractInterceptUrlConfigurer可以看出,configure方法中调用了一个postProcess方法,该方法用于生成FilterSecurityInterceptor对象,在本系列文章前面第一章以及列出来的FilterChainProxy拦截器链对象,可以知道FilterSecurityInterceptor对象就属于FilterChainProxy拦截器链中的对象,并且是处在最后一个位置。
+
+到此处,安全配置类的作用已经提现出来了,就是向sharedObject中添加过滤器,并最终注入到FilterChainProxy中。
+
+### 2. AbstractConfiguredSecurityBuilder的doBuild()方法
+随着configurers集合元素的注入,下面就是进行构建工作,调用doBuild()方法。
+
+```
+ @Override
+ protected final O doBuild() throws Exception {
+ synchronized (configurers) {
+ // 设置构建状态为初始化中
+ buildState = BuildState.INITIALIZING;
+
+ // 进行初始化前的工作
+ beforeInit();
+ // 初始化
+ init();
+
+ // 设置构建状态为配置中
+ buildState = BuildState.CONFIGURING;
+
+ // 配置前的工作
+ beforeConfigure();
+ // 调用配置
+ configure();
+
+ // 设置构建状态为构建中
+ buildState = BuildState.BUILDING;
+
+ // 执行构建核心逻辑
+ O result = performBuild();
+
+ // 设置构建状态为已构建
+ buildState = BuildState.BUILT;
+
+ return result;
+ }
+ }
+
+```
+beforeInit()和beforeConfigure()是一个空方法体,没有逻辑。
+```
+ protected void beforeInit() throws Exception {
+ }
+ protected void beforeConfigure() throws Exception {
+ }
+```
+
+```
+ private void init() throws Exception {
+ // 调用getConfigurers()方法获取this.configurers的所有value值,并以List集合的形式返回
+ Collection> configurers = getConfigurers();
+ // 遍历configurers,并依次调用安全配置类的init方法
+ for (SecurityConfigurer configurer : configurers) {
+ // 调用安全配置类的init初始化方法
+ configurer.init((B) this);
+ }
+
+ for (SecurityConfigurer configurer : configurersAddedInInitializing) {
+ configurer.init((B) this);
+ }
+ }
+```
+
+这需要注意的是,init和configure方法是有接口SecurityConfigurer接口定义的,但其实现以由SecurityConfigurerAdapter这个抽象的适配器类实现了,所以最终的安全配置类可重写init()和configure(),也可以不重写。所以可以发现,很多安全配置类是重写没有init()方法的。
+
+未完待续....
\ No newline at end of file
From a3d85d167e811aefff960412ca319a0ec51e7577 Mon Sep 17 00:00:00 2001
From: CoderBruis <37364336+coderbruis@users.noreply.github.com>
Date: Mon, 10 Aug 2020 07:17:53 +0800
Subject: [PATCH 003/184] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E6=96=87?=
=?UTF-8?q?=E7=AB=A0=E8=87=B3readme=E4=B8=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 717a171..57102a6 100644
--- a/README.md
+++ b/README.md
@@ -72,7 +72,7 @@ Tip:
- SpringSecurity版本:5.1.0.RELEASE
- [从零开始系统学习SpringSecurity和OAuth2(一)—— 初识SpringSecurity](https://github.com/coderbruis/JavaSourceLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%80%EF%BC%89%E2%80%94%E2%80%94%20%E5%88%9D%E8%AF%86SpringSecurity.md)
- [从零开始系统学习SpringSecurity和OAuth2(二)—— 安全过滤器FilterChainProxy](https://github.com/coderbruis/JavaSourceLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94%20%E5%AE%89%E5%85%A8%E8%BF%87%E6%BB%A4%E5%99%A8FilterChainProxy.md)
-
+ - [从零开始系统学习SpringSecurity和OAuth2(三)—— WebSecurity建造核心逻辑](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%89%EF%BC%89%E2%80%94%E2%80%94%20WebSecurity%E5%BB%BA%E9%80%A0%E6%A0%B8%E5%BF%83%E9%80%BB%E8%BE%91.md)
持续更新中...
From 407abb33e7f44f42acea6c7d68a686780129b911 Mon Sep 17 00:00:00 2001
From: CoderBruis <37364336+coderbruis@users.noreply.github.com>
Date: Mon, 10 Aug 2020 07:18:16 +0800
Subject: [PATCH 004/184] Update README.md
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 57102a6..b19d1fc 100644
--- a/README.md
+++ b/README.md
@@ -73,6 +73,8 @@ Tip:
- [从零开始系统学习SpringSecurity和OAuth2(一)—— 初识SpringSecurity](https://github.com/coderbruis/JavaSourceLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%80%EF%BC%89%E2%80%94%E2%80%94%20%E5%88%9D%E8%AF%86SpringSecurity.md)
- [从零开始系统学习SpringSecurity和OAuth2(二)—— 安全过滤器FilterChainProxy](https://github.com/coderbruis/JavaSourceLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94%20%E5%AE%89%E5%85%A8%E8%BF%87%E6%BB%A4%E5%99%A8FilterChainProxy.md)
- [从零开始系统学习SpringSecurity和OAuth2(三)—— WebSecurity建造核心逻辑](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%89%EF%BC%89%E2%80%94%E2%80%94%20WebSecurity%E5%BB%BA%E9%80%A0%E6%A0%B8%E5%BF%83%E9%80%BB%E8%BE%91.md)
+
+
持续更新中...
From f5fe9c0e4f090fb58513dac666e5a98c60ad86eb Mon Sep 17 00:00:00 2001
From: LuoHaiYang
Date: Mon, 10 Aug 2020 14:19:50 +0800
Subject: [PATCH 005/184] =?UTF-8?q?=E6=9B=B4=E6=96=B0SpringSecurity?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...\345\210\235\350\257\206SpringSecurity.md" | 22 ++-
...70\345\277\203\351\200\273\350\276\221.md" | 139 ++++++++++++++++--
...46\273\244\345\231\250FilterChainProxy.md" | 18 ++-
3 files changed, 163 insertions(+), 16 deletions(-)
diff --git "a/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md" "b/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md"
index 4f94be4..b6eb258 100644
--- "a/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md"
+++ "b/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md"
@@ -1,4 +1,21 @@
-@[toc]
+
+- [前言](#前言)
+- [正文](#正文)
+ - [1. 初识SpringSecurity](#1-初识springsecurity)
+ - [2. Spring Security项目核心jar包介绍](#2-spring-security项目核心jar包介绍)
+ - [3. SpringSecurity核心注解](#3-springsecurity核心注解)
+ - [3.1 @EnableWebSecurity](#31-enablewebsecurity)
+ - [3.2 @EnableGlobalAuthentication](#32-enableglobalauthentication)
+ - [3.3 @EnableGlobalMethodSecurity](#33-enableglobalmethodsecurity)
+ - [4. SpringSecurity核心组件](#4-springsecurity核心组件)
+ - [4.1 认证](#41-认证)
+ - [4.2 授权](#42-授权)
+ - [5. SpringSecurity中的Filter](#5-springsecurity中的filter)
+ - [5.1 FilterChainProxy以及其内部的Filter](#51-filterchainproxy以及其内部的filter)
+- [总结](#总结)
+- [参考](#参考)
+- [相关文章](#相关文章)
+
## 前言
相信了解过SpringSecurity或者是OAuth2的读者,会发现网上会有非常多的相关文章,或是纯概念的,或是带有demo的,无论是哪种类型的文章,本人去阅读之后,对于整个框架的概念还是一知半解,也仅仅是实现了某些功能、某些效果而已,若遇到某些问题时无从下手,只能去百度去Google。这是因为对于SpringSecurity和OAuth2的知识没有一个整体概念的把握,知识体系没有形成系统,遂决定写一个关于SpringSecurity和OAuth2的系列专栏,在构建自己知识体系的同时还希望能帮助有同样困惑的同学。
@@ -167,4 +184,5 @@ int vote(Authentication authentication, S object,
- [《Spring Security Reference》](https://docs.spring.io/spring-security/site/docs/current/reference/html5/#preface)
## 相关文章
-- [从零开始系统学习SpringSecurity和OAuth2(二)—— 安全过滤器FilterChainProxy](https://blog.csdn.net/CoderBruis/article/details/107604400)
\ No newline at end of file
+- [从零开始系统学习SpringSecurity和OAuth2(二)—— 安全过滤器FilterChainProxy](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94%20%E5%AE%89%E5%85%A8%E8%BF%87%E6%BB%A4%E5%99%A8FilterChainProxy.md)
+系统学习SpringSecurity和OAuth2(三)—— WebSecurity建造核心逻辑](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%89%EF%BC%89%E2%80%94%E2%80%94%20WebSecurity%E5%BB%BA%E9%80%A0%E6%A0%B8%E5%BF%83%E9%80%BB%E8%BE%91.md- [从零开始)
\ No newline at end of file
diff --git "a/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md" "b/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md"
index 94a450b..3d6cfb6 100644
--- "a/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md"
+++ "b/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\211\357\274\211\342\200\224\342\200\224 WebSecurity\345\273\272\351\200\240\346\240\270\345\277\203\351\200\273\350\276\221.md"
@@ -1,4 +1,12 @@
-@[toc]
+
+ - [前言](#前言)
+ - [正文](#正文)
+ - [1. AbstractConfiguredSecurityBuilder中安全配置类](#1-abstractconfiguredsecuritybuilder中安全配置类)
+ - [2. AbstractConfiguredSecurityBuilder的doBuild()方法](#2-abstractconfiguredsecuritybuilder的dobuild方法)
+ - [3. WebSecurity中的performBuild()方法](#3-websecurity中的performbuild方法)
+- [总结](#总结)
+- [相关文章](#相关文章)
+
## 前言
相信了解过SpringSecurity或者是OAuth2的读者,会发现网上会有非常多的相关文章,或是纯概念的,或是带有demo的,无论是哪种类型的文章,本人去阅读之后,对于整个框架的概念还是一知半解,也仅仅是实现了某些功能、某些效果而已,若遇到某些问题时无从下手,只能去百度去Google。这是因为对于SpringSecurity和OAuth2的知识没有一个整体概念的把握,知识体系没有形成系统,遂决定写一个关于SpringSecurity和OAuth2的系列专栏,在建造自己知识体系的同时还希望能帮助有同样困惑的同学。
@@ -9,7 +17,7 @@
## 正文
### 1. AbstractConfiguredSecurityBuilder中安全配置类
-SpringSecurity通过SecurityConfigurer来构建FilterChainProxy,构建前还需要进行配置。因此AbstractConfiguredSecurityBuilder还需要注入配置组件SecurityConfigurer,初始化配置组件SecurityConfigurer,调用SecurityConfigurer的configure方法。
+SpringSecurity通过SecurityConfigurer来建造FilterChainProxy,建造前还需要进行配置。因此AbstractConfiguredSecurityBuilder还需要注入配置组件SecurityConfigurer,初始化配置组件SecurityConfigurer,调用SecurityConfigurer的configure方法。
在AbstractConfiguredSecurityBuilder类中,看下安全配置类的定义:‘
@@ -28,7 +36,7 @@ private final LinkedHashMap>, List>, List> configurers = getConfigurers();
+
+ for (SecurityConfigurer configurer : configurers) {
+ // 遍历configurers,然后依次调用其configure方法
+ configurer.configure((B) this);
+ }
+ }
+```
+
+在前面已经已经以ExpressionUrlAuthorizationConfigurer为例,去查看安全配置类configure方法的作用,都知道安全配置类的configure方法是用于将过滤器添加到sharedObject缓存中。
+
+经过init()和configure()方法的执行,以及可以开始进行建造工作了,因而调用performBuild()方法执行建造过程。
+
+```
+ protected abstract O performBuild() throws Exception;
+```
+可以看到在AbstractConfiguredSecurityBuilder中,performBuild是以抽象方法的形式存在的,所以实现逻辑都在其子类中。
+
+
+
+这里HttpSecurity和WebSecurity类名这么像,有什么异同呢?
+
+> HttpSecurity
+
+HttpSecurity允许为特定的http请求配置基于Web的安全特性。默认情况下,HttpSecurity将应用于所有请求,但是如果需要限制请求,则可以通过RequestMatcher或其他类似方法来进行限制。
+
+> WebSecurity
+
+而WebSecurity是通过WebSecurityConfiguration创建的,用于去创建类FilterChainProxy。在SpringSecurity中,WebSecurity通过HttpSecurity来对某些请求进行拦截限制。
+
+> 区别
+
+WebSecurity用于建造FilterChainProxy,WebSecurity是包含HttpSecurity的一个更大的概念,而HttpSecurity仅是用于建造FilterChainProxy中的一个SecurityFilterChain。
+
+
+### 3. WebSecurity中的performBuild()方法
+WebSecurity重写了AbstractConfiguredSecurityBuilder的perfomBuild()方法,核心逻辑如下:
+
+```
+ @Override
+ protected Filter performBuild() throws Exception {
+ Assert.state(
+ !securityFilterChainBuilders.isEmpty(),
+ () -> "At least one SecurityBuilder extends SecurityFilterChain> needs to be specified. "
+ + "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
+ + "More advanced users can invoke "
+ + WebSecurity.class.getSimpleName()
+ + ".addSecurityFilterChainBuilder directly");
+ // 获取chain大小
+ int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
+ // 设置安全过滤器链集合
+ List securityFilterChains = new ArrayList<>(
+ chainSize);
+ // 遍历igoredRequests集合,该集合表示存储着忽略拦截的请求
+ for (RequestMatcher ignoredRequest : ignoredRequests) {
+ securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
+ }
+ for (SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
+ // 先调用securityFilterChainBuilder执行build()方法,然后添加进securityFilterChains集合中。之列build()方法是去迭代执行doBuild()逻辑。
+ securityFilterChains.add(securityFilterChainBuilder.build());
+ }
+
+ // 创建一个FilterChainProxy对象,传入一个securityFilterChains对象
+ FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
+ if (httpFirewall != null) {
+ // 设置http防火墙属性
+ filterChainProxy.setFirewall(httpFirewall);
+ }
+ filterChainProxy.afterPropertiesSet();
+
+ Filter result = filterChainProxy;
+ if (debugEnabled) {
+ logger.warn("\n\n"
+ + "********************************************************************\n"
+ + "********** Security debugging is enabled. *************\n"
+ + "********** This may include sensitive information. *************\n"
+ + "********** Do not use in a production system! *************\n"
+ + "********************************************************************\n\n");
+ result = new DebugFilter(filterChainProxy);
+ }
+
+ // 执行一个线程
+ postBuildAction.run();
+ return result;
+ }
+
+```
+
+在performBuild()方法中,会执行securityFilterChainBuilder的build()方法,该方法又会去迭代执行doBuild()方法,最终返回一个SecurityFilterChain对象。
+
+
+综上,本文对WebSecurity的建造逻辑进行了概括性的讲解,更加深入的内容还需要进行代码debug跟踪深入查看,这样才能加深对于WebSecurity的理解。
+
+## 总结
+- 安全配置类是在HttpSecurity、XXConfigurerAdapter等类中进行添加
+- WebSecurity和HttpSecurity区别在于,WebSecurity是用于建造FilterChainProxy的,它是包含HttpSecurity;而HttpSecurity是用于对请求进行限制,同时还用于建造DefaultSecurityFilterChain
+- 安全配置类主要是通过configure方法向sharedObject缓存对象中添加过滤器,并最终添加进FilterChainProxy过滤器链中
+- WebSecurity建造FilterChainProxy的核心逻辑可以笼统的分为三步:安全配置了初始化、安全配置类configure的调用、performBuild的调用
+
+## 相关文章
+- [从零开始系统学习SpringSecurity和OAuth2(一)—— 初识SpringSecurity](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%80%EF%BC%89%E2%80%94%E2%80%94%20%E5%88%9D%E8%AF%86SpringSecurity.md)
+- [从零开始系统学习SpringSecurity和OAuth2(二)—— 安全过滤器FilterChainProxy](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94%20%E5%AE%89%E5%85%A8%E8%BF%87%E6%BB%A4%E5%99%A8FilterChainProxy.md)
\ No newline at end of file
diff --git "a/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 \345\256\211\345\205\250\350\277\207\346\273\244\345\231\250FilterChainProxy.md" "b/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 \345\256\211\345\205\250\350\277\207\346\273\244\345\231\250FilterChainProxy.md"
index 8602c1c..a14939f 100644
--- "a/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 \345\256\211\345\205\250\350\277\207\346\273\244\345\231\250FilterChainProxy.md"
+++ "b/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 \345\256\211\345\205\250\350\277\207\346\273\244\345\231\250FilterChainProxy.md"
@@ -1,4 +1,17 @@
-@[toc]
+- [前言](#前言)
+- [正文](#正文)
+ - [1. FilterChainProxy什么时候注入Spring容器中的](#1--filterchainproxy什么时候注入spring容器中的)
+ - [2. WebSecurityConfiguration类](#2-websecurityconfiguration类)
+ - [3. WebSecurity类](#3-websecurity类)
+ - [4. AbstractConfiguredSecurityBuilder类](#4-abstractconfiguredsecuritybuilder类)
+ - [5. SecurityConfigurer类](#5-securityconfigurer类)
+ - [6. doBuild()方法](#6-dobuild方法)
+ - [7. WebSecurity什么时候被创建的?](#7-websecurity什么时候被创建的)
+- [总结](#总结)
+- [参考](#参考)
+- [相关文章](#相关文章)
+
+
## 前言
相信了解过SpringSecurity或者是OAuth2的读者,会发现网上会有非常多的相关文章,或是纯概念的,或是带有demo的,无论是哪种类型的文章,本人去阅读之后,对于整个框架的概念还是一知半解,也仅仅是实现了某些功能、某些效果而已,若遇到某些问题时无从下手,只能去百度去Google。这是因为对于SpringSecurity和OAuth2的知识没有一个整体概念的把握,知识体系没有形成系统,遂决定写一个关于SpringSecurity和OAuth2的系列专栏,在建造自己知识体系的同时还希望能帮助有同样困惑的同学。
@@ -356,4 +369,5 @@ performBuild()方法是AbstractConfiguredSecurityBuilder提供的抽象方法,
- [深入浅出Spring Security(一):三句话解释框架原理](https://blog.csdn.net/zimou5581/article/details/102457672)
## 相关文章
-- [从零开始系统学习SpringSecurity和OAuth2(一)—— 初识SpringSecurity](https://blog.csdn.net/CoderBruis/article/details/107297547)
\ No newline at end of file
+- [从零开始系统学习SpringSecurity和OAuth2(一)—— 初识SpringSecurity](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%80%EF%BC%89%E2%80%94%E2%80%94%20%E5%88%9D%E8%AF%86SpringSecurity.md)
+- [从零开始系统学习SpringSecurity和OAuth2(三)—— WebSecurity建造核心逻辑](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%89%EF%BC%89%E2%80%94%E2%80%94%20WebSecurity%E5%BB%BA%E9%80%A0%E6%A0%B8%E5%BF%83%E9%80%BB%E8%BE%91.md)
From ef23d8451824f07a64f881439d8f6b6f3a3b24e0 Mon Sep 17 00:00:00 2001
From: LuoHaiYang
Date: Mon, 10 Aug 2020 14:21:57 +0800
Subject: [PATCH 006/184] =?UTF-8?q?=E6=9B=B4=E6=96=B0SpringSecurity?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...24\342\200\224 \345\210\235\350\257\206SpringSecurity.md" | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git "a/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md" "b/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md"
index b6eb258..9f61fff 100644
--- "a/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md"
+++ "b/note/SpringSecurity/\344\273\216\351\233\266\345\274\200\345\247\213\347\263\273\347\273\237\345\255\246\344\271\240SpringSecurity\345\222\214OAuth2\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224 \345\210\235\350\257\206SpringSecurity.md"
@@ -176,13 +176,10 @@ int vote(Authentication authentication, S object,
## 总结
本片文章粗略的讲解了SpringSecurity里的几个核心概念,包括:核心注解、认证和授权的核心组件以及SpringSecurity中的FilterChainProxy,整个SpringSecurity框架就是围绕着这几个核心概念运行,下面几章将会深入分析每个核心概念的底层运行机制。
-> 作者本人github中开发并维护着一个后端基于Dubbo+SpringBoot+SpringSecurity+OAuth2而前端基于Vue的前后端分离电商项目,其中还维护着一个实战专栏用于详细记录开发该电商项目时遇到的技术难点以及解决方案,感兴趣读者可以前往查看,后端地址如下:
-> [https://github.com/coderbruis/Distributed-mall](https://github.com/coderbruis/Distributed-mall)
-
## 参考
- [《spring-security-architecture》](https://spring.io/guides/topicals/spring-security-architecture)
- [《Spring Security Reference》](https://docs.spring.io/spring-security/site/docs/current/reference/html5/#preface)
## 相关文章
- [从零开始系统学习SpringSecurity和OAuth2(二)—— 安全过滤器FilterChainProxy](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94%20%E5%AE%89%E5%85%A8%E8%BF%87%E6%BB%A4%E5%99%A8FilterChainProxy.md)
-系统学习SpringSecurity和OAuth2(三)—— WebSecurity建造核心逻辑](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%89%EF%BC%89%E2%80%94%E2%80%94%20WebSecurity%E5%BB%BA%E9%80%A0%E6%A0%B8%E5%BF%83%E9%80%BB%E8%BE%91.md- [从零开始)
\ No newline at end of file
+- [从零开始系统学习SpringSecurity和OAuth2(三)—— WebSecurity建造核心逻辑](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/SpringSecurity/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0SpringSecurity%E5%92%8COAuth2%EF%BC%88%E4%B8%89%EF%BC%89%E2%80%94%E2%80%94%20WebSecurity%E5%BB%BA%E9%80%A0%E6%A0%B8%E5%BF%83%E9%80%BB%E8%BE%91.md)
\ No newline at end of file
From c61504128c600393d2b071275448a0266c9b6fe5 Mon Sep 17 00:00:00 2001
From: LuoHaiYang
Date: Tue, 11 Aug 2020 07:00:58 +0800
Subject: [PATCH 007/184] =?UTF-8?q?=E4=B8=BAJDK=E6=96=87=E7=AB=A0=E6=B7=BB?=
=?UTF-8?q?=E5=8A=A0=E7=9B=AE=E5=BD=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...245\345\255\246\344\271\240ThreadLocal.md" | 20 +++++++++++++++++++
...02\357\274\210\344\270\200\357\274\211.md" | 20 +++++++++++++++++++
...02\357\274\210\344\272\214\357\274\211.md" | 16 +++++++++++++++
...01\344\270\216\345\216\237\347\220\206.md" | 16 ++++++++++-----
4 files changed, 67 insertions(+), 5 deletions(-)
diff --git "a/note/JDK/\344\270\200\347\257\207\346\226\207\347\253\240\345\277\253\351\200\237\346\267\261\345\205\245\345\255\246\344\271\240ThreadLocal.md" "b/note/JDK/\344\270\200\347\257\207\346\226\207\347\253\240\345\277\253\351\200\237\346\267\261\345\205\245\345\255\246\344\271\240ThreadLocal.md"
index 5d4337a..fbe3c0c 100644
--- "a/note/JDK/\344\270\200\347\257\207\346\226\207\347\253\240\345\277\253\351\200\237\346\267\261\345\205\245\345\255\246\344\271\240ThreadLocal.md"
+++ "b/note/JDK/\344\270\200\347\257\207\346\226\207\347\253\240\345\277\253\351\200\237\346\267\261\345\205\245\345\255\246\344\271\240ThreadLocal.md"
@@ -1,3 +1,23 @@
+
+- [前言](#前言)
+- [正文](#正文)
+ - [1. 适用(使用)场景](#1-适用使用场景)
+ - [1.1 线程资源持有(线程隔离)](#11-线程资源持有线程隔离)
+ - [1.2 线程资源一致性](#12-线程资源一致性)
+ - [1.3 线程安全](#13-线程安全)
+ - [1.4 分布式计算](#14-分布式计算)
+ - [1.5 在SqlSessionManager中的应用](#15-在sqlsessionmanager中的应用)
+ - [1.6 在Spring框架中的TransactionContextHolder中的应用](#16-在spring框架中的transactioncontextholder中的应用)
+ - [2. 源码学习](#2-源码学习)
+ - [2.1 ThreadLocal内部使用了哪些数据结构?](#21-threadlocal内部使用了哪些数据结构)
+ - [2.2 源码分析](#22-源码分析)
+ - [3. 总结](#3-总结)
+ - [3.1 ThreadLocal的适用场景](#31-threadlocal的适用场景)
+ - [3.2 哪些开源框架、源码使用到了ThreadLocal](#32-哪些开源框架源码使用到了threadlocal)
+ - [3.3 关于内存泄漏](#33-关于内存泄漏)
+ - [3.4 其他](#34-其他)
+- [引用](#引用)
+
## 前言
最近开始空闲起来了,深入学习系列以及自我提升系列都得提上日程了。本次学习的ThreadLocal,是由JDK提供的一个用于存储每个线程本地副本信息的类,它的编写者就是著名的并发包大神Doug Lea。要想深入学习一个类,首先得先阅读它的官方类注释:
diff --git "a/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240String\346\272\220\347\240\201\344\270\216\345\272\225\345\261\202\357\274\210\344\270\200\357\274\211.md" "b/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240String\346\272\220\347\240\201\344\270\216\345\272\225\345\261\202\357\274\210\344\270\200\357\274\211.md"
index 16fd799..4418513 100644
--- "a/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240String\346\272\220\347\240\201\344\270\216\345\272\225\345\261\202\357\274\210\344\270\200\357\274\211.md"
+++ "b/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240String\346\272\220\347\240\201\344\270\216\345\272\225\345\261\202\357\274\210\344\270\200\357\274\211.md"
@@ -1,3 +1,23 @@
+
+- [前言](#前言)
+- [正文](#正文)
+ - [1 基础](#1-基础)
+ - [1.1 String的修饰符与实现类](#11-string的修饰符与实现类)
+ - [1.2 String类的成员变量](#12-string类的成员变量)
+ - [1.2.1 String是通过char数组来保存字符串的](#121-string是通过char数组来保存字符串的)
+ - [1.2.2 String类的属性hash](#122-string类的属性hash)
+ - [1.2.3 serialVersionUID属性作为String类的序列化ID](#123-serialversionuid属性作为string类的序列化id)
+ - [1.2.4 serialPersistentFields属性](#124-serialpersistentfields属性)
+ - [1.3 创建String对象](#13-创建string对象)
+ - [1.4 String被设计为不可变性的原因](#14-string被设计为不可变性的原因)
+ - [2 深入String](#2-深入string)
+ - [2.1 先了解一下JAVA内存区域](#21-先了解一下java内存区域)
+ - [2.2 String与JAVA内存区域](#22-string与java内存区域)
+ - [2.3 String的intern方法](#23-string的intern方法)
+ - [2.3.1 重新理解使用new和字面量创建字符串的两种方式](#231-重新理解使用new和字面量创建字符串的两种方式)
+ - [2.3.2 解析](#232-解析)
+
+
## 前言
不想成为一个只会使用API的攻城狮,也不甘于现状想深入学习JDK。
diff --git "a/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240String\346\272\220\347\240\201\344\270\216\345\272\225\345\261\202\357\274\210\344\272\214\357\274\211.md" "b/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240String\346\272\220\347\240\201\344\270\216\345\272\225\345\261\202\357\274\210\344\272\214\357\274\211.md"
index 83bd4be..c8bcb33 100644
--- "a/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240String\346\272\220\347\240\201\344\270\216\345\272\225\345\261\202\357\274\210\344\272\214\357\274\211.md"
+++ "b/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240String\346\272\220\347\240\201\344\270\216\345\272\225\345\261\202\357\274\210\344\272\214\357\274\211.md"
@@ -1,3 +1,19 @@
+
+- [前言](#前言)
+ [正文](#正文)
+ - [1. String的equals方法](#1-string的equals方法)
+ - [2. String的hashcode方法](#2-string的hashcode方法)
+ - [3. String的hashcode()和equals()](#3-string的hashcode和equals)
+ - [4. String的compareTo()方法](#4-string的compareto方法)
+ - [5. String的startWith(String prefix)方法](#5-string的startwithstring-prefix方法)
+ - [6. String的endsWith(String suffix)方法](#6-string的endswithstring-suffix方法)
+ - [7. String的indexOf(int ch)方法](#7-string的indexofint-ch方法)
+ - [8. String的split(String regex, int limit)方法](#8-string的splitstring-regex-int-limit方法)
+ - [8.1 源码分析1](#81-源码分析1)
+ - [8.2 源码分析2](#82-源码分析2)
+- [总结](#总结)
+
+
## 前言
不想成为一个只会使用API的攻城狮,也不甘于现状想深入学习JDK源码。
diff --git "a/note/JDK/\346\267\261\345\205\245\350\247\243\350\257\273CompletableFuture\346\272\220\347\240\201\344\270\216\345\216\237\347\220\206.md" "b/note/JDK/\346\267\261\345\205\245\350\247\243\350\257\273CompletableFuture\346\272\220\347\240\201\344\270\216\345\216\237\347\220\206.md"
index 2c6087d..5a43c54 100644
--- "a/note/JDK/\346\267\261\345\205\245\350\247\243\350\257\273CompletableFuture\346\272\220\347\240\201\344\270\216\345\216\237\347\220\206.md"
+++ "b/note/JDK/\346\267\261\345\205\245\350\247\243\350\257\273CompletableFuture\346\272\220\347\240\201\344\270\216\345\216\237\347\220\206.md"
@@ -1,3 +1,14 @@
+
+- [1 前言](#1-前言)
+- [2 正文](#2-正文)
+ - [2.1 JDK官方文档解释](#21-jdk官方文档解释)
+ - [2.2 使用下CompletableFuture的API](#22-使用下completablefuture的api)
+ - [2.3 源码分析](#23-源码分析)
+ - [Completion](#completion)
+ - [CompletionStage](#completionstage)
+ - [总结](#总结)
+
+
## 1 前言
最近在看公司源码,发现有些服务大量使用到了CompletableFuture,学了这么久Java,对这个类还是挺陌生的,实在惭愧。于是利用了业余时间认真学习并总结了下CompletableFuture的特性以及用法。
@@ -555,11 +566,6 @@ main线程会在asyncSupplyStage()方法中返回d,就是我们的“依赖任
3. CompletableFuture中有“源任务”和“依赖任务”,“源任务”的完成能够触发“依赖任务”的执行,这里的完成可以是返回正常结果或者是异常。
4. CompletableFuture默认使用ForkJoinPool,也可以使用指定线程池来执行任务。
-文中的测试用例都在下列源码的JdkLearn模块的test目录下。
-
-> 源码地址:https://github.com/coderbruis/JavaSourceLearning
-
-
参考文档:
- 《JDK8官方文档》
From 185685ad6e752a7671344789fbb46e7ef8b00f2e Mon Sep 17 00:00:00 2001
From: LuoHaiYang
Date: Tue, 11 Aug 2020 12:38:32 +0800
Subject: [PATCH 008/184] =?UTF-8?q?=E4=B8=BASpring=E6=96=87=E7=AB=A0?=
=?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=9B=AE=E5=BD=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...226\347\225\245\346\250\241\345\274\217.md" | 18 ++++++++++++++++++
...5\273\272Spring\346\272\220\347\240\201.md" | 9 +++++++++
...250\357\274\210\344\270\212\357\274\211.md" | 12 +++++++++++-
...250\357\274\210\344\270\213\357\274\211.md" | 8 ++++++++
...7\224\250Spring\346\272\220\347\240\201.md" | 7 +++++++
5 files changed, 53 insertions(+), 1 deletion(-)
diff --git "a/note/Spring/\344\273\216Spring\346\272\220\347\240\201\344\270\255\345\255\246\344\271\240\342\200\224\342\200\224\347\255\226\347\225\245\346\250\241\345\274\217.md" "b/note/Spring/\344\273\216Spring\346\272\220\347\240\201\344\270\255\345\255\246\344\271\240\342\200\224\342\200\224\347\255\226\347\225\245\346\250\241\345\274\217.md"
index 57b6c9a..a35adcc 100644
--- "a/note/Spring/\344\273\216Spring\346\272\220\347\240\201\344\270\255\345\255\246\344\271\240\342\200\224\342\200\224\347\255\226\347\225\245\346\250\241\345\274\217.md"
+++ "b/note/Spring/\344\273\216Spring\346\272\220\347\240\201\344\270\255\345\255\246\344\271\240\342\200\224\342\200\224\347\255\226\347\225\245\346\250\241\345\274\217.md"
@@ -1,3 +1,21 @@
+
+- [前言](#前言)
+- [正文](#正文)
+ - [一、先看看初学者都会的多重if-else判断](#一先看看初学者都会的多重if-else判断)
+ - [二、策略模式实现](#二策略模式实现)
+ - [2.1 定义一个策略接口: Strategy.class](#21-定义一个策略接口-strategyclass)
+ - [2.2 创建接口的实现类](#22-创建接口的实现类)
+ - [2.3 创建Context类](#23-创建context类)
+ - [2.4 创建实现类](#24-创建实现类)
+ - [三、策略模式的优缺点](#三策略模式的优缺点)
+ - [3.1 优点](#31-优点)
+ - [3.2 缺点](#32-缺点)
+ - [3.3 策略模式中的三个角色](#33-策略模式中的三个角色)
+ - [四、在Spring源码中应用的策略模式](#四在spring源码中应用的策略模式)
+ - [4.1 Spring源码中的BeanDefinitionReader](#41-spring源码中的beandefinitionreader)
+ - [4.2 Spring源码中ResourceLoader](#42-spring源码中resourceloader)
+ - [五、总结](#五总结)
+
## 前言
策略模式听起来高大上,吓退了很多初学小伙伴,下面就来揭开策略模式的神秘面纱,并看看在Spring源码中是如何应用到策略模式的。
diff --git "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224\345\234\250IDEA\344\270\255\346\236\204\345\273\272Spring\346\272\220\347\240\201.md" "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224\345\234\250IDEA\344\270\255\346\236\204\345\273\272Spring\346\272\220\347\240\201.md"
index 2c72693..aadf1ba 100644
--- "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224\345\234\250IDEA\344\270\255\346\236\204\345\273\272Spring\346\272\220\347\240\201.md"
+++ "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\270\200\357\274\211\342\200\224\342\200\224\345\234\250IDEA\344\270\255\346\236\204\345\273\272Spring\346\272\220\347\240\201.md"
@@ -1,3 +1,12 @@
+
+- [前言——万里长征的第一步](#前言万里长征的第一步)
+- [准备工作](#准备工作)
+ - [Spring源码包下载](#spring源码包下载)
+ - [gradle工具下载](#gradle工具下载)
+ - [编译Spring源码](#编译spring源码)
+ - [将Spring源码导入IDEA中](#将spring源码导入idea中)
+
+
## 前言——万里长征的第一步
要学习Spring源码,导入Spring源码到IDE是必不可少的一步,因为Spring源码各个包、各个类之间的各种关联关系非常复杂。如果仅仅是通过Spring源码文档来看,相信没多少人能坚持学下去。因此将Spring源码包导入IDE是非常必要的。本人使用IDEA较多,所以也就将Spring源码导入至IDEA中。
diff --git "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\212\357\274\211.md" "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\212\357\274\211.md"
index e277b1b..6e5eb8e 100644
--- "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\212\357\274\211.md"
+++ "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\212\357\274\211.md"
@@ -1,4 +1,14 @@
-
+
+- [前言](#前言)
+- [进入正题](#进入正题)
+ - [DefaultListableBeanFactory](#defaultlistablebeanfactory)
+ - [XmlBeanDefinitionReader](#xmlbeandefinitionreader)
+ - [通过xml配置文件来初始化容器](#通过xml配置文件来初始化容器)
+ - [提问环节](#提问环节)
+ - [深入理解Spring容器如何创建bean和初始化bean](#深入理解spring容器如何创建bean和初始化bean)
+ - [在web容器中初始化spring容器](#在web容器中初始化spring容器)
+- [参考](#参考)
+
## 前言
**Spring版本: Spring5-0-3**
diff --git "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\213\357\274\211.md" "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\213\357\274\211.md"
index 5af08d2..a180928 100644
--- "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\213\357\274\211.md"
+++ "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\213\357\274\211.md"
@@ -1,3 +1,11 @@
+
+- [前言](#前言)
+- [在web容器中初始化spring容器](#在web容器中初始化spring容器)
+ - [SpringIOC容器和Web容器](#springioc容器和web容器)
+ - [ContextLoaderListener](#contextloaderlistener)
+- [总结](#总结)
+
+
## 前言
继上一篇文章深入了解了在普通的Spring应用程序中如何创建并启动SpringIOC容器的,下面,深入学习一下在web容器中,是如何创建、初始化并启动SpringIOC容器的。
diff --git "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\350\241\245\345\205\205\347\257\207\357\274\211\342\200\224\342\200\224\347\250\213\345\272\217\350\260\203\347\224\250Spring\346\272\220\347\240\201.md" "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\350\241\245\345\205\205\347\257\207\357\274\211\342\200\224\342\200\224\347\250\213\345\272\217\350\260\203\347\224\250Spring\346\272\220\347\240\201.md"
index 6bab61d..e61a805 100644
--- "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\350\241\245\345\205\205\347\257\207\357\274\211\342\200\224\342\200\224\347\250\213\345\272\217\350\260\203\347\224\250Spring\346\272\220\347\240\201.md"
+++ "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\350\241\245\345\205\205\347\257\207\357\274\211\342\200\224\342\200\224\347\250\213\345\272\217\350\260\203\347\224\250Spring\346\272\220\347\240\201.md"
@@ -1,3 +1,10 @@
+
+- [前言](#前言)
+- [正文](#正文)
+ - [一、使用Spring源码的test测试文件来尝试启动Spring源码](#一使用spring源码的test测试文件来尝试启动spring源码)
+ - [二、解决问题](#二解决问题)
+ - [三、验证是否成功调用Spring源码](#三验证是否成功调用spring源码)
+
## 前言
前段时间一直忙于其他事情,没空下来继续研究Spring源码。最近有空又重拾Spring源码,打算继续深入研究。
From 309be5611b00373e4ac1b4831822a40078614bd2 Mon Sep 17 00:00:00 2001
From: LuoHaiYang
Date: Wed, 12 Aug 2020 10:13:18 +0800
Subject: [PATCH 009/184] =?UTF-8?q?[U]=E6=9B=B4=E6=96=B0readme?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index b19d1fc..fefc2ab 100644
--- a/README.md
+++ b/README.md
@@ -20,11 +20,27 @@
-源码深入学习:Spring源码、SpringBoot源码、SpringAOP源码、SpringSecurity源码、OAuth2源码、JDK源码、Netty源码
+Java流行框架源码分析,学习以及总结。
-Tip:
-如果读者电脑无法浏览到github图片,则需要设置hosts配置文件, 解决办法:[解决GitHub网页githubusercontent地址无法访问问题
-](https://zhuanlan.zhihu.com/p/107691233)
+框架包括:
+
+1. Spring源码【更新中】
+2. SpringBoot源码【更新中】
+3. SpringAOP源码【更新中】
+4. SpringSecurity源码【更新中】
+5. SpringSecurity OAuth2源码【更新中】
+6. JDK源码【更新中】
+7. Netty源码(待)
+8. MyBatis(待)
+9. Dubbo源码(待)
+10. SpringCloud(待)
+
+> 为什么要分析、学习源码?
+
+学习一个框架的源码,不仅在实际使用时如果出现问题,可以快速定位出问题,找到问题原因并解决,同时还可以学习到框架的架构思想以与设计模式。当然,学习框架底层源码还可以提升我们自身的水平,在大厂面试时能够在众多面试者中脱颖而出。因此学习框架虽然枯燥乏味,但罗马并非一日建成的,所以平时之余就要多学习框架底层源码,
+这样在用到的时候就能游刃有余。
+
+> Tip:如果读者电脑无法浏览到github图片,则需要设置hosts配置文件, 解决办法:[解决GitHub网页githubusercontent地址无法访问问题](https://zhuanlan.zhihu.com/p/107691233)
# 目录
@@ -80,6 +96,6 @@ Tip:
# 支持
- 开源不易,各位帅哥美女们star支持一下....
+ 原创不易,各位帅哥美女star支持下...
From 150d962b4d1d233552e644e70ad592faf3f88dbd Mon Sep 17 00:00:00 2001
From: LuoHaiYang
Date: Wed, 12 Aug 2020 10:16:35 +0800
Subject: [PATCH 010/184] =?UTF-8?q?[U]=E6=9B=B4=E6=96=B0readme?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 ++
note/images/zan.jpg | Bin 0 -> 30114 bytes
2 files changed, 2 insertions(+)
create mode 100644 note/images/zan.jpg
diff --git a/README.md b/README.md
index fefc2ab..f81158f 100644
--- a/README.md
+++ b/README.md
@@ -96,6 +96,8 @@ Java流行框架源码分析,学习以及总结。
# 支持
+ 
+
原创不易,各位帅哥美女star支持下...
diff --git a/note/images/zan.jpg b/note/images/zan.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8fa13a72d336dff64249fb646485c9cd07fa48d1
GIT binary patch
literal 30114
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