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

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


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


http://www.kler.cn/a/598638.html

相关文章:

  • vue3之写一个aichat---实现聊天逻辑
  • OpenRAND可重复的随机数生成库
  • git 合并多次提交 commit
  • 【xiaozhi赎回之路-2:语音可以自己配置就是用GPT本地API】
  • display: contens的使用
  • python爬虫Redis数据库
  • 【MyDB】5-索引管理之4-单元测试
  • Jupyter Notebook 常用命令(自用)
  • AI安全学习(刚开始,未完版)
  • git 命令回退版本
  • Kafka 八股文
  • python 游戏开发cocos2d库安装与使用
  • 【推荐项目】056-高校学籍管理系统
  • 回归——数学公式推导全过程
  • 【前端】webstorm中运行一个前端项目
  • C++核心语法快速整理
  • SpringBoot集成MQTT客户端
  • HarmonyOS:通过键值型数据库实现数据持久化
  • Mysql 安装教程和Workbench的安装教程以及workbench的菜单栏汉化
  • 响应式CMS架构优化SEO与用户体验