public RequestMatcher getRequestMatcher() {
return requestMatcher;
}
public List getFilters() {
return filters;
}
public boolean matches(HttpServletRequest request) {
return requestMatcher.matches(request);
}
@Override
public String toString() {
return "[ " + requestMatcher + ", " + filters + “]”;
}
}
DefaultSecurityFilterChain 只是对 SecurityFilterChain 中的方法进行了实现,并没有特别值得说的地方,松哥也就不啰嗦了。
那么从上面的介绍中,大家可以看到,DefaultSecurityFilterChain 其实就相当于是 Spring Security 中的过滤器链,一个 DefaultSecurityFilterChain 代表一个过滤器链,如果系统中存在多个过滤器链,则会存在多个 DefaultSecurityFilterChain 对象。
接下来我们把 HttpSecurity 的这几个父类捋一捋。
1.2 SecurityBuilder
public interface SecurityBuilder {
O build() throws Exception;
}
SecurityBuilder 就是用来构建过滤器链的,在 HttpSecurity 实现 SecurityBuilder 时,传入的泛型就是 DefaultSecurityFilterChain,所以 SecurityBuilder#build 方法的功能很明确,就是用来构建一个过滤器链出来。
1.3 HttpSecurityBuilder
HttpSecurityBuilder 看名字就是用来构建 HttpSecurity 的。不过它也只是一个接口,具体的实现在 HttpSecurity 中,接口定义如下:
public interface HttpSecurityBuilder<H extends HttpSecurityBuilder> extends
SecurityBuilder {
<C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C getConfigurer(
Class clazz);
<C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(
Class clazz);
void setSharedObject(Class sharedType, C object);
C getSharedObject(Class sharedType);
H authenticationProvider(AuthenticationProvider authenticationProvider);
H userDetailsService(UserDetailsService userDetailsService) throws Exception;
H addFilterAfter(Filter filter, Class<? extends Filter> afterFilter);
H addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter);
H addFilter(Filter filter);
}
这里的方法比较简单:
-
getConfigurer 获取一个配置对象。Spring Security 过滤器链中的所有过滤器对象都是由 xxxConfigure 来进行配置的,这里就是获取这个 xxxConfigure 对象。
-
removeConfigurer 移除一个配置对象。
-
setSharedObject/getSharedObject 配置/获取由多个 SecurityConfigurer 共享的对象。
-
authenticationProvider 方法表示配置验证器。
-
userDetailsService 配置数据源接口。
-
addFilterAfter 在某一个过滤器之前添加过滤器。
-
addFilterBefore 在某一个过滤器之后添加过滤器。
-
addFilter 添加一个过滤器,该过滤器必须是现有过滤器链中某一个过滤器或者其扩展。
这便是 HttpSecurityBuilder 中的功能,这些接口在 HttpSecurity 中都将得到实现。
1.4 AbstractSecurityBuilder
AbstractSecurityBuilder 类实现了 SecurityBuilder 接口,该类中主要做了一件事,就是确保整个构建只被构建一次。
public abstract class AbstractSecurityBuilder implements SecurityBuilder {
private AtomicBoolean building = new AtomicBoolean();
private O object;
public final O build() throws Exception {
if (this.building.compareAndSet(false, true)) {
this.object = doBuild();
return this.object;
}
throw new AlreadyBuiltException(“This object has already been built”);
}
public final O getObject() {
if (!this.building.get()) {
throw new IllegalStateException(“This object has not been built”);
}
return this.object;
}
protected abstract O doBuild() throws Exception;
}
可以看到,这里重新定义了 build 方法,并设置 build 方法为 final 类型,无法被重写,在 build 方法中,通过 AtomicBoolean 实现该方法只被调用一次。具体的构建逻辑则定义了新的抽象方法 doBuild,将来在实现类中通过 doBuild 方法定义构建逻辑。
1.5 AbstractConfiguredSecurityBuilder
AbstractSecurityBuilder 方法的实现类就是 AbstractConfiguredSecurityBuilder。
AbstractConfiguredSecurityBuilder 中所做的事情就比较多了,我们分别来看。
首先 AbstractConfiguredSecurityBuilder 中定义了一个枚举类,将整个构建过程分为 5 种状态,也可以理解为构建过程生命周期的五个阶段,如下:
private enum BuildState {
UNBUILT(0),
INITIALIZING(1),
CONFIGURING(2),
BUILDING(3),
BUILT(4);
private final int order;
BuildState(int order) {
this.order = order;
}
public boolean isInitializing() {
return INITIALIZING.order == order;
}
public boolean isConfigured() {
return order >= CONFIGURING.order;
}
}
五种状态分别是 UNBUILT、INITIALIZING、CONFIGURING、BUILDING 以及 BUILT。另外还提供了两个判断方法,isInitializing 判断是否正在初始化,isConfigured 表示是否已经配置完毕。
AbstractConfiguredSecurityBuilder 中的方法比较多,松哥在这里列出来两个关键的方法和大家分析:
private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
Assert.notNull(configurer, “configurer cannot be null”);
Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
.getClass();
synchronized (configurers) {
if (buildState.isConfigured()) {
throw new IllegalStateException("Cannot apply " + configurer
- " to already built object");
}
List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
.get(clazz) : null;
if (configs == null) {
configs = new ArrayList<>(1);
}
configs.add(configurer);
this.configurers.put(clazz, configs);
if (buildState.isInitializing()) {
this.configurersAddedInInitializing.add(configurer);
}
}
}
private Collection<SecurityConfigurer<O, B>> getConfigurers() {
List<SecurityConfigurer<O, B>> result = new ArrayList<>();
for (List<SecurityConfigurer<O, B>> configs : this.configurers.values()) {
result.addAll(configs);
}
return result;
}
第一个就是这个 add 方法,这相当于是在收集所有的配置类。将所有的 xxxConfigure 收集起来存储到 configurers 中,将来再统一初始化并配置,configurers 本身是一个 LinkedHashMap ,key 是配置类的 class,value 是一个集合,集合里边放着 xxxConfigure 配置类。当需要对这些配置类进行集中配置的时候,会通过 getConfigurers 方法获取配置类,这个获取过程就是把 LinkedHashMap 中的 value 拿出来,放到一个集合中返回。
另一个方法就是 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;
}
}
private void init() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.init((B) this);
}
for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
configurer.init((B) this);
}
}
private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.configure((B) this);
}
}
在 AbstractSecurityBuilder 类中,过滤器的构建被转移到 doBuild 方法上面了,不过在 AbstractSecurityBuilder 中只是定义了抽象的 doBuild 方法,具体的实现在 AbstractConfiguredSecurityBuilder。
doBuild 方法就是一边更新状态,进行进行初始化。
beforeInit 是一个预留方法,没有任何实现。
init 方法就是找到所有的 xxxConfigure,挨个调用其 init 方法进行初始化。
beforeConfigure 是一个预留方法,没有任何实现。
configure 方法就是找到所有的 xxxConfigure,挨个调用其 configure 方法进行配置。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://img-blog.csdnimg.cn/img_convert/9cd92f8f0184338f22b33e2563e68d02.jpeg)
线程、数据库、算法、JVM、分布式、微服务、框架、Spring相关知识
一线互联网P7面试集锦+各种大厂面试集锦
学习笔记以及面试真题解析
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
备注Java获取)**
![img](https://img-blog.csdnimg.cn/img_convert/9cd92f8f0184338f22b33e2563e68d02.jpeg)
线程、数据库、算法、JVM、分布式、微服务、框架、Spring相关知识
[外链图片转存中…(img-y0LGc28T-1712485330113)]
一线互联网P7面试集锦+各种大厂面试集锦
[外链图片转存中…(img-xh2hWcEj-1712485330113)]
学习笔记以及面试真题解析
[外链图片转存中…(img-ahygzsx8-1712485330114)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!