Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 489ba8a

Browse filesBrowse files
committed
添加dubbo和SpringSecurity源码学习
1 parent 99a5d12 commit 489ba8a
Copy full SHA for 489ba8a

File tree

Expand file treeCollapse file tree

3 files changed

+208
-1
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+208
-1
lines changed
Open diff view settings
Collapse file

‎README.md‎

Copy file name to clipboardExpand all lines: README.md
+1-1Lines changed: 1 addition & 1 deletion
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Tip:
2929
# 目录
3030

3131
- 项目导入
32-
将整个JavaSourceLearning导入IDEA中,然后选中项目pom.xml文件右键,open as maven project然后等待maven下载相应jar包即可。
32+
将整个JavaSourceCodeLearning导入IDEA中,然后选中项目pom.xml文件右键,open as maven project然后等待maven下载相应jar包即可。
3333

3434
- JDK源码学习
3535
- JDK版本:1.8.0_77
Collapse file
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## 前言
2+
3+
想要深入学习Dubbo,最好的方式就是阅读并调用Dubbo源码。接下来先来动手搭建一个Dubbo源码。
4+
5+
## 正文
6+
7+
### 1. 下载源码
8+
9+
步骤:
10+
11+
1. 先从dubbo源码官网github中fork一份到自己的github仓库中。
12+
2. 使用命令:git branch v2.7.7。 切换到分支2.7.7。
13+
14+
未完待续...
Collapse file
+193Lines changed: 193 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
@[toc]
2+
## 前言
3+
相信了解过SpringSecurity或者是OAuth2的读者,会发现网上会有非常多的相关文章,或是纯概念的,或是带有demo的,无论是哪种类型的文章,本人去阅读之后,对于整个框架的概念还是一知半解,也仅仅是实现了某些功能、某些效果而已,若遇到某些问题时无从下手,只能去百度去Google。这是因为对于SpringSecurity和OAuth2的知识没有一个整体概念的把握,知识体系没有形成系统,遂决定写一个关于SpringSecurity和OAuth2的系列专栏,在建造自己知识体系的同时还希望能帮助有同样困惑的同学。
4+
5+
============== 分割线 ==============
6+
7+
上一章已经讲解到了SpringSecurity用到了建造者模式来建造FilterChainProxy。本片就来详细分析下WebSecurity的核心逻辑以及AbstractConfiguredSecurityBuilder的doBuild()方法。
8+
9+
## 正文
10+
11+
### 1. AbstractConfiguredSecurityBuilder中安全配置类
12+
SpringSecurity通过SecurityConfigurer来构建FilterChainProxy,构建前还需要进行配置。因此AbstractConfiguredSecurityBuilder还需要注入配置组件SecurityConfigurer,初始化配置组件SecurityConfigurer,调用SecurityConfigurer的configure方法。
13+
14+
在AbstractConfiguredSecurityBuilder类中,看下安全配置类的定义:‘
15+
16+
```
17+
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>();
18+
```
19+
这是定义的安全配置器的子类Map集合,这个configurers就是用于初始化以及配置FilterChainProxy中的filters用的。Map集合中,Key是SecurityConfigurer的子类的Class类型,Value是SecurityConfigurer的list集合。
20+
21+
作为一个成员变量,自然会有方法从外部注入安全配置类。在AbstractConfiguredSecurityBuilder的类中,定义了add方法。
22+
23+
```
24+
private <C extends SecurityConfigurer<O, B>> void add(C configurer) throws Exception {
25+
Assert.notNull(configurer, "configurer cannot be null");
26+
// 获取安全配置类的Class类型
27+
Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
28+
.getClass();
29+
// 同步去操作安全配置类集合
30+
synchronized (configurers) {
31+
// 查看构建状态是否是已经配置
32+
if (buildState.isConfigured()) {
33+
throw new IllegalStateException("Cannot apply " + configurer
34+
+ " to already built object");
35+
}
36+
// 如果allowConfigurersOfSameType为true,则从configurers集合中获取clazz类型的安全配置类集合
37+
List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
38+
.get(clazz) : null;
39+
if (configs == null) {
40+
// 初始化安全配置类结合
41+
configs = new ArrayList<SecurityConfigurer<O, B>>(1);
42+
}
43+
// 将安全配置类添加至configs的list集合中
44+
configs.add(configurer);
45+
// 以clazz为key,configs为value存入configurers的LinkedHashMap集合中
46+
this.configurers.put(clazz, configs);
47+
if (buildState.isInitializing()) {
48+
this.configurersAddedInInitializing.add(configurer);
49+
}
50+
}
51+
}
52+
53+
```
54+
55+
通过IDEA来查看下哪些地方调用了add方法
56+
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020080918440196.png)
57+
58+
看下apply方法
59+
```
60+
// 传入的C是SecurityConfigurerAdapter的子类,
61+
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
62+
throws Exception {
63+
// 传入objectPostProcessor,该对象用于创建各种“实例”,具体什么作用下问会讲解,请留意
64+
configurer.addObjectPostProcessor(objectPostProcessor);
65+
// 将当前对象设置为构建者
66+
configurer.setBuilder((B) this);
67+
// 调用add方法,向configurers集合中添加configurer
68+
add(configurer);
69+
return configurer;
70+
}
71+
72+
```
73+
74+
继续查看apply方法有哪些地方调用了的
75+
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200809224904457.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NvZGVyQnJ1aXM=,size_16,color_FFFFFF,t_70)
76+
图上的HttpSecurity的getOrApply方法值得注意一下,查看其方法
77+
```
78+
private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(
79+
C configurer) throws Exception {
80+
// 从configurers集合中获取安全配置类
81+
C existingConfig = (C) getConfigurer(configurer.getClass());
82+
if (existingConfig != null) {
83+
// 如果存在则直接返回该安全配置类
84+
return existingConfig;
85+
}
86+
// 如果不存在则调用apply方法去应用该安全配置类,并缓存到configurers集合中
87+
return apply(configurer);
88+
}
89+
90+
```
91+
92+
getOrApply方法主要是从configurers集合中获取配置类,如果存在则直接返回,否则则应用该配置类。
93+
94+
继续查看getOrApply有哪些地方在调用。这下终于看到了安全配置类了。
95+
96+
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200809225003886.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NvZGVyQnJ1aXM=,size_16,color_FFFFFF,t_70)
97+
这里有一个问题值得思考,这些配置类到底是干嘛用的?这里就以ExpressionUrlAuthorizationConfigurer配置类为例,看下其类内部configure方法逻辑。
98+
99+
找了一圈,发现configure的实现是在ExpressionUrlAuthorizationConfigurer的抽象父类AbstractInterceptUrlConfigurer定义的。
100+
101+
```
102+
@Override
103+
public void configure(H http) throws Exception {
104+
// 创建元数据,该抽象方法由ExpressionUrlAuthorizationConfigurer定义,返回一个ExpressionBasedFilterInvocationSecurityMetadataSource对象
105+
FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);
106+
// 如果配置失败,则数据源配置失败
107+
if (metadataSource == null) {
108+
return;
109+
}
110+
// 创建一个FilterSecurityInterceptor对象
111+
FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(
112+
http, metadataSource, http.getSharedObject(AuthenticationManager.class));
113+
if (filterSecurityInterceptorOncePerRequest != null) {
114+
securityInterceptor
115+
.setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
116+
}
117+
// 通过objectPostProcessor创建一个securityInterceptor实例对象
118+
securityInterceptor = postProcess(securityInterceptor);
119+
http.addFilter(securityInterceptor);
120+
// 将实例对象存入SharedObject缓存中
121+
http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
122+
}
123+
124+
```
125+
126+
从ExpressionUrlAuthorizationConfigurer的抽象父类AbstractInterceptUrlConfigurer可以看出,configure方法中调用了一个postProcess方法,该方法用于生成FilterSecurityInterceptor对象,在本系列文章前面第一章以及列出来的FilterChainProxy拦截器链对象,可以知道FilterSecurityInterceptor对象就属于FilterChainProxy拦截器链中的对象,并且是处在最后一个位置。
127+
128+
到此处,安全配置类的作用已经提现出来了,就是向sharedObject中添加过滤器,并最终注入到FilterChainProxy中。
129+
130+
### 2. AbstractConfiguredSecurityBuilder的doBuild()方法
131+
随着configurers集合元素的注入,下面就是进行构建工作,调用doBuild()方法。
132+
133+
```
134+
@Override
135+
protected final O doBuild() throws Exception {
136+
synchronized (configurers) {
137+
// 设置构建状态为初始化中
138+
buildState = BuildState.INITIALIZING;
139+
140+
// 进行初始化前的工作
141+
beforeInit();
142+
// 初始化
143+
init();
144+
145+
// 设置构建状态为配置中
146+
buildState = BuildState.CONFIGURING;
147+
148+
// 配置前的工作
149+
beforeConfigure();
150+
// 调用配置
151+
configure();
152+
153+
// 设置构建状态为构建中
154+
buildState = BuildState.BUILDING;
155+
156+
// 执行构建核心逻辑
157+
O result = performBuild();
158+
159+
// 设置构建状态为已构建
160+
buildState = BuildState.BUILT;
161+
162+
return result;
163+
}
164+
}
165+
166+
```
167+
beforeInit()和beforeConfigure()是一个空方法体,没有逻辑。
168+
```
169+
protected void beforeInit() throws Exception {
170+
}
171+
protected void beforeConfigure() throws Exception {
172+
}
173+
```
174+
175+
```
176+
private void init() throws Exception {
177+
// 调用getConfigurers()方法获取this.configurers的所有value值,并以List集合的形式返回
178+
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
179+
// 遍历configurers,并依次调用安全配置类的init方法
180+
for (SecurityConfigurer<O, B> configurer : configurers) {
181+
// 调用安全配置类的init初始化方法
182+
configurer.init((B) this);
183+
}
184+
185+
for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
186+
configurer.init((B) this);
187+
}
188+
}
189+
```
190+
191+
这需要注意的是,init和configure方法是有接口SecurityConfigurer接口定义的,但其实现以由SecurityConfigurerAdapter这个抽象的适配器类实现了,所以最终的安全配置类可重写init()和configure(),也可以不重写。所以可以发现,很多安全配置类是重写没有init()方法的。
192+
193+
未完待续....

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.