spring-security原理与应用系列:建造者

目录

1.构建过程

AbstractSecurityBuilder

AbstractConfiguredSecurityBuilder

WebSecurity

2.建造者类图

SecurityBuilder

​​​​​​​AbstractSecurityBuilder

​​​​​​​AbstractConfiguredSecurityBuilder

​​​​​​​WebSecurity

3.小结


        紧接上一篇文章,这一篇我们来看看构建者WebSecurity是如何构建出一个过滤器对象springSecurityFilterChain的。

1.构建过程

        点击类WebSecurityConfiguration的方法springSecurityFilterChain()里的this.webSecurity.build(),如下所示:

AbstractSecurityBuilder

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {

... ...

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");
}

        在这里,build()方法调用了doBuild()方法。

        点击doBuild()方法,如下所示:

​​​​​​​AbstractConfiguredSecurityBuilder

@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、init、beforeConfigure、configure、performBuild的5个步骤。

        点击最后一步performBuild,如下所示:

​​​​​​​WebSecurity

public final class WebSecurity extends
      AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements
      SecurityBuilder<Filter>, ApplicationContextAware {

... ...

@Override
protected Filter performBuild() throws Exception {
   int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
   List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(
         chainSize);
   for (RequestMatcher ignoredRequest : ignoredRequests) {
      securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
   }
   for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
      securityFilterChains.add(securityFilterChainBuilder.build());
   }
   FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
   if (httpFirewall != null) {
      filterChainProxy.setFirewall(httpFirewall);
   }
   filterChainProxy.afterPropertiesSet();
   Filter result = filterChainProxy;
   if (debugEnabled) {
      result = new DebugFilter(filterChainProxy);
   }
   postBuildAction.run();
   return result;
}

        在这里,可以看到构建的过滤器类是FilterChainProxy。至于这个类的具体结构,我们后续再进行深入的探究。

        我们先看看在系统运行时,这个FilterChainProxy内部都包含有哪些Filter。

        设置断点,如下所示:

​​​​​​​过滤器代理

        在这里,我们看到了FilterChainProxy对象内部包含了很多的Filter。后续再深入了解这些Filter的配置过程及应用场景。

        接下来我们重点学习一下与WebSecurity构建者相关的类图模型。

2.建造者类图

       在这里,AbstractSecurityBuilder、AbstractConfiguredSecurityBuilder、WebSecurity都是我们在上面一节中有接触过的类。

​​​​​​​SecurityBuilder

        这个接口是建造者模式的顶级接口,含有建造者对外暴露的构建对象的一个接口方法 build() 。

        代码如下:

public interface SecurityBuilder<O> {
   O build() throws Exception;
}

​​​​​​​AbstractSecurityBuilder

        这个类是SecurityBuilder接口的抽象子类,实现了接口的build()方法,为确保构建对象只被构建一次,对父接口方法 build() 进行了原子判断,从而保证每次只构建一次。另外,定义了一个抽象方法 doBuild() 供子类扩展。

        代码如下:

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
   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;
}

​​​​​​​AbstractConfiguredSecurityBuilder

        实现父类的doBuild()方法,这里是真正执行构建的地方。

        首先,使用了建造者模式定义了构建对象的所有步骤;

        其次,使用了模板方法模式,将构建对象的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

        代码如下:

public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>extends AbstractSecurityBuilder<O> {... ...public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {add(configurer);return configurer;}@SuppressWarnings("unchecked")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);}}}@Overrideprotected 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;}}protected void beforeInit() throws Exception {}protected void beforeConfigure() throws Exception {}protected abstract O performBuild() throws Exception;@SuppressWarnings("unchecked")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);}}@SuppressWarnings("unchecked")private void configure() throws Exception {Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();for (SecurityConfigurer<O, B> configurer : configurers) {configurer.configure((B) this);}}
}

​​​​​​​WebSecurity

        实现父类的 performBuild()方法,这是构建对象的所有步骤的最后一个步。通过实现父类方法的方式来定义具体的执行内容。

        WebSecurity 的目标是构建 FilterChainProxy 对象,即构建核心过滤器 springSecurityFilterChain。

        代码如下:

public final class WebSecurity extends
      AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements
      SecurityBuilder<Filter>, ApplicationContextAware {
      ... ...
   @Override
   protected Filter performBuild() throws Exception {
      int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
      List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
            chainSize);
      for (RequestMatcher ignoredRequest : ignoredRequests) {
         securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
      }
      for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
         securityFilterChains.add(securityFilterChainBuilder.build());
      }
      FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
      if (httpFirewall != null) {
         filterChainProxy.setFirewall(httpFirewall);
      }
      filterChainProxy.afterPropertiesSet();

      Filter result = filterChainProxy;
      postBuildAction.run();
      return result;
   }
}

3.小结

        整个构建过程由beforeInit、init、beforeConfigure、configure、performBuild5大步骤组成。技术层面使用了建造者模式和模板方法模式。


疏漏之处恭请雅正,良策佳议敬候惠示,凡所赐教必当铭感于心。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/74332.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenHarmony子系统开发 - 电池管理(二)

OpenHarmony子系统开发 - 电池管理&#xff08;二&#xff09; 五、充电限流限压定制开发指导 概述 简介 OpenHarmony默认提供了充电限流限压的特性。在对终端设备进行充电时&#xff0c;由于环境影响&#xff0c;可能会导致电池温度过高&#xff0c;因此需要对充电电流或电…

xy轴不等比缩放问题——AUTOCAD c#二次开发

在 AutoCAD .net api里&#xff0c;部分实体&#xff0c;像文字、属性、插入块等&#xff0c;是不支持非等比缩放的。 如需对AutoCAD中图形进行xyz方向不等比缩放&#xff0c;则需进行额外的函数封装。 选择图元&#xff0c;指定缩放基准点&#xff0c;scaleX 0.5, scaleY …

如何在 HTML 中创建一个有序列表和无序列表,它们的语义有何不同?

大白话如何在 HTML 中创建一个有序列表和无序列表&#xff0c;它们的语义有何不同&#xff1f; 1. HTML 中有序列表和无序列表的基本概念 在 HTML 里&#xff0c;列表是一种用来组织信息的方式。有序列表就是带有编号的列表&#xff0c;它可以让内容按照一定的顺序呈现&#…

kafka的文章

1.面试的问题 要点 至多一次、恰好一次数据一致性超时重试、幂等消息顺序消息挤压延时消息 1.1 kafaka 生产消息的过程。 在消息发送的过程中&#xff0c;涉及到了两个线程&#xff0c;一个是main 线程&#xff0c;一个是sender 线程。在main 线程中创建了一个双端队列 Reco…

以mysql 为例,增删改查语法及其他高级特性

以下是 MySQL 的 增删改查语法及 高级特性的详细整理&#xff0c;结合示例说明&#xff1a; 1. 基础操作&#xff08;CRUD&#xff09; (1) 创建数据&#xff08;INSERT&#xff09; -- 单条插入 INSERT INTO users (id, name, email) VALUES (1, Alice, aliceexample.com);…

Postman最新详细安装及使用教程【附安装包】

一、Postman介绍 ‌Postman是一个功能强大的API测试工具&#xff0c;主要用于模拟和测试各种HTTP请求&#xff0c;支持GET、POST、PUT、DELETE等多种请求方法。‌通过Postman&#xff0c;用户可以发送请求并查看返回的响应&#xff0c;检查响应的内容和状态&#xff0c;从而验…

第十三章 : Names in Templates_《C++ Templates》notes

Names in Templates 重难点多选题设计题 重难点 1. 名称分类与基本概念 知识点&#xff1a; 限定名&#xff08;Qualified Name&#xff09;&#xff1a;使用::或.显式指定作用域的名称&#xff08;如std::vector&#xff09;非限定名&#xff08;Unqualified Name&#xff0…

整合vue+Element UI 开发管理系统

1、 安装 Node.js 和 npm 确保安装了 Node.js 和 npm。可以通过 Node.js 官网 下载。 2、 创建 Vue 项目 安装cli npm install -g vue/cli 使用 Vue CLI 创建一个新的 Vue 项目。 vue create admin-system cd admin-system npm run serve 出现这个页面表示vue创建成功 安…

3. 轴指令(omron 机器自动化控制器)——>MC_Stop

机器自动化控制器——第三章 轴指令 9 MC_Stop变量▶输入变量▶输出变量▶输入输出变量 功能说明▶指令详情▶时序图▶重启运动指令▶多重启动运动指令▶异常 MC_Stop 使轴减速停止。 指令名称FB/FUN图形表现ST表现MC_Stop强制停止FBMC_Stop_instance (Axis :《参数》 ,Execu…

C#中修饰符——abstract、virtual

一、多态简介 在面向对象编程的过程中&#xff0c;多态体现出来的是【一个接口&#xff0c;多个功能】&#xff1b;多态性体现在2个方面&#xff1a; 1、程序运行时&#xff0c;在方法参数、集合或数组等位置&#xff0c;派生类对象可以作为基类的对象处理&#xff1b;这样该对…

Spring Boot + Spring Integration整合MQTT打造双向通信客户端

1. 概述 本文分两个章节讲解MQTT相关的知识&#xff0c;第一部份主要讲解MQTT的原理和相关配置&#xff0c;第二个章节主要讲和Spring boot的integration相结合代码的具体实现&#xff0c;如果想快速实现功能&#xff0c;可直接跳过第一章节查看第二章讲。 1.1 MQTT搭建 为了…

2025前端面试题记录

vue项目目录的执行顺序是怎么样的&#xff1f; 1、package.json   在执行npm run dev时&#xff0c;会在当前目录寻找package.json文件&#xff0c;此文件包含了项目的名称版本、项目依赖等相关信息。 2、webpack.config.js(会被vue-cli脚手架隐藏) 3、vue.config.js   对…

专题|Python贝叶斯网络BN动态推理因果建模:MLE/Bayes、有向无环图DAG可视化分析呼吸疾病、汽车效能数据2实例合集

原文链接&#xff1a;https://tecdat.cn/?p41199 作为数据科学家&#xff0c;我们始终在探索能够有效处理复杂系统不确定性的建模工具。本专题合集系统性地解构了贝叶斯网络&#xff08;BN&#xff09;这一概率图模型在当代数据分析中的创新应用&#xff0c;通过开源工具bnlea…

WX小程序

下载 package com.sky.utils;import com.alibaba.fastjson.JSONObject; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.Cl…

Vulnhub-wordpress通关攻略

姿势一、后台修改模板拿WebShell 第一步&#xff1a;进⼊Vulhub靶场并执⾏以下命令开启靶场&#xff1b;在浏览器中访问并安装好.... 第二步&#xff1a;找到外观--编辑--404.php&#xff0c;将原内容删除并修改为一句话木马&#xff0c;点击更新--File edited successfully. &…

Spring Boot(十六):拦截器Interceptor

拦截器的简介 拦截器&#xff08;Interceptor&#xff09;​是Spring框架中的概​念&#xff0c;它同样适​用于Spring Boot&#xff0c;​因为Spring Boot是基于Spring框架的。拦截器是​一种AOP&#xff08;面向切面编程&#xff09;​的轻量级实现方式&#xff0c;它允许我…

Kotlin v2.1.20 发布,标准库又有哪些变化?

大家吼哇&#xff01;就在三小时前&#xff0c;Kotlin v2.1.20 发布了&#xff0c;更新的内容也已经在官网上更新&#xff1a;What’s new in Kotlin 2.1.20 。 我粗略地看了一下&#xff0c;下面为大家选出一些我比较感兴趣、且你可能也会感兴趣的内容。 注意&#xff01;这里…

开源链动2+1模式、AI智能名片与S2B2C商城小程序源码在社交电商渠道拓宽中的协同应用研究

摘要&#xff1a;本文基于"开源链动21模式""AI智能名片""S2B2C商城小程序源码"三大技术要素&#xff0c;探讨社交电商时代商家渠道拓宽的创新路径。通过解析各技术的核心机制与应用场景&#xff0c;结合京东便利店等实际案例&#xff0c;论证其对…

【蓝桥杯速成】| 10.回溯切割

前面两篇内容我们都是在做有关回溯问题的组合应用 今天的题目主题是&#xff1a;回溯法在切割问题的应用 题目一&#xff1a;分割回文串 问题描述 131. 分割回文串 - 力扣&#xff08;LeetCode&#xff09; 给你一个字符串 s&#xff0c;请你将 s 分割成一些 子串&#xff…

【嵌入式硬件】三款DCDC调试笔记

关于开关电源芯片&#xff0c;重点关注输入电源范围、输出电流、最低压降。 1.MP9943: 以MP9943为例&#xff0c;输入电压范围4-36V&#xff0c;输出最大电流3A&#xff0c;最低压降为0.3V 调整FB使正常输出为5.06V 给定6V空载、5V空载、5V带2A负载的情况&#xff1a; 6V带2A…