当前位置: 首页 > news >正文

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

   @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;
      }
   }
   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大步骤组成。技术层面使用了建造者模式和模板方法模式。


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

相关文章:

  • AI Agent开发大全第七课-个人如何申请到靠谱的AI
  • git日常学习
  • 五、重学C++—类(封装继承)
  • QT实现WPS功能
  • AI:如何用 MeloSpyGUI 和 MeloSpySuite 生成爵士音乐文件
  • 如何让自动驾驶汽车“看清”世界?坐标映射与数据融合概述
  • Java学习路线(便于理解)
  • “统计视角看世界”专栏阅读引导
  • 接上一主题,直接对二进制进行加密,密钥不写入电脑。
  • .NET 9 彻底改变了 API 文档:从 Swashbuckle(Swagger) 到 Scalar
  • AI比人脑更强,因为被植入思维模型【17】万物联系思维模型
  • 低功耗蓝牙(BLE)方案设计实战指南
  • 程序代码篇---SQLite数据库存储信息
  • 操作系统的特征
  • 程序设计语言的分类和特点
  • 学习本地部署DeepSeek的过程(基于ollama)
  • 产品经理如何管理需求池
  • Spring AOP 核心概念与实践指南
  • 图解模糊推理过程(超详细步骤)
  • DeepSeek、Grok 与 ChatGPT 4.5:新一代大模型架构与推理能力深度解析
  • 上海市第二十届青少年科技节启动:为期半年,推出百余项活动
  • 泽连斯基:俄代表团级别低,没人能做决定
  • 广西:坚决拥护党中央对蓝天立进行审查调查的决定
  • 龚正市长调研闵行区,更加奋发有为地稳增长促转型,久久为功增强发展后劲
  • 马上评|中学生被操场地面烫伤,谁的“大课间”?
  • 俄方代表团抵达土耳其,俄乌直接谈判有望于当地时间上午重启