网站建设开发外包公司,wordpress 新建表单,做网站得叫什么软件,重庆在建工程项目一、Builder设计模式
WebSecurity、HttpSecurity、AuthenticationManagerBuilder 都是框架中的构建者#xff0c;把他们放到一起看看他们的共同特点#xff1a;
查看AuthenticationManagerBuilder的继承结构图#xff1a; 查看HttpSecurity的继承结构图#xff1a; 查看W…一、Builder设计模式
WebSecurity、HttpSecurity、AuthenticationManagerBuilder 都是框架中的构建者把他们放到一起看看他们的共同特点
查看AuthenticationManagerBuilder的继承结构图 查看HttpSecurity的继承结构图 查看WebSecurity的继承结构图 可以看出他们都有这样一条继承树
|- SecurityBuilder|- AbstractSecurityBuilder|- AbstractConfiguredSecurityBuilder二、SecurityBuilder
/*** Interface for building an Object** param O The type of the Object being built* author Rob Winch* since 3.2*/
public interface SecurityBuilderO {/*** Builds the object and returns it or null.* return the Object to be built or null if the implementation allows it.* throws Exception if an error occurred when building the Object*/O build() throws Exception;}SecurityBuilder是一个接口当调用它的 build() 方法时会创建一个对象。将要创建的对象类型由泛型 O 限制。这个接口是所有构造器的顶级接口也是Spring Security 框架中使用Builder设计模式的基础接口。
三、AbstractSecurityBuilder
/*** A base {link SecurityBuilder} that ensures the object being built is only built one* time.** param O the type of Object that is being built* author Rob Winch**/
public abstract class AbstractSecurityBuilderO implements SecurityBuilderO {// 标记对象是否处于创建中private AtomicBoolean building new AtomicBoolean();private O object;Overridepublic final O build() throws Exception {if (this.building.compareAndSet(false, true)) {// 对象的实际底构建过程再 doBuild() 方法中实现this.object doBuild();return this.object;}throw new AlreadyBuiltException(This object has already been built);}/*** 获取已生成的对象。如果尚未构建则会引发异常。* return the Object that was built*/public final O getObject() {if (!this.building.get()) {throw new IllegalStateException(This object has not been built);}return this.object;}/*** 子类需实现这个方法来执行对象构建。* return the object that should be returned by {link #build()}.* throws Exception if an error occurs*/protected abstract O doBuild() throws Exception;}AbstractSecurityBuilder是SecurityBuilder的一个基础实现抽象类提供构造器的基础流程和控制能够确保对象O只被创建一次。
这个类很简单 定义了一个原子操作的对象用来标记当前对象是否处于构造中 private AtomicBoolean building new AtomicBoolean();实现SecurityBuilder接口的 build() 方法。 调用 doBuild() 方法完成构造并且在调用 doBuild() 之前需要原子修改 building 为 true只有修改成功才能执行 doBuild() 方法这间接的保证了对象只构造一次确保构造的唯一性和原子性。 定义一个 getObject() 方法方便获取构造的对象。 定义抽象方法 doBuild() 加入模板模式交给子类自行实现。
四、AbstractConfiguredSecurityBuilder 源码注释 A base SecurityBuilder that allows SecurityConfigurer to be applied to it. This makes modifying the SecurityBuilder a strategy that can be customized and broken up into a number of SecurityConfigurer objects that have more specific goals than that of the SecurityBuilder. 一个基本的SecurityBuilder允许将SecurityConfigurer应用于它。这使得修改SecurityBuilder的策略可以自定义并分解为许多SecurityConfigurer对象这些对象具有比SecurityBuilder更具体的目标。 For example, a SecurityBuilder may build an DelegatingFilterProxy, but a SecurityConfigurer might populate the SecurityBuilder with the filters necessary for session management, form based login, authorization, etc. 请参阅: WebSecurity 作者: Rob Winch 类型形参: O – The object that this builder returns 此构造器返回的对象 B – The type of this builder (that is returned by the base class) 此构造器的类型由基类返回 它继承自 AbstractSecurityBuilder 在此之上又做了一些扩展。先来看看里面都有什么 4.1 内部静态枚举类 BuildState
这个枚举类用来表示应用程序构造器构造对象的状态代码相对简单就不粘贴源码了。
枚举类中只有一个 int 类型的成员变量 order 表示状态编号: UNBUILT(0) 未构造 构造器的 build 方法被调用之前的状态 INITIALIZING(1) 初始化中 构造器的 build 方法第一次被调用到所有 SecurityConfigurer 的 init 方法都被调用完这期间都是 INITIALIZING 状态 CONFIGURING(2) 配置中 表示从所有的 SecurityConfigurer 的 init 方法都被调用完直到所有 configure 方法都被调用 意思就是所有配置器都初始化了直到配置都被调用这段时间都时 CONFIGURING 状态 BUILDING(3) 对象构造中 表示已经执行完所有的 SecurityConfigurer 的 configure 方法到刚刚执行完 AbstractConfiguredSecurityBuilder 的 performBuild 方法这期间 意思就是从将所有配置器的配置都配置完成开始到构造完这个对象这段时间都是 BUILDING 状态 BUILT(4) 对象已经构造完成 表示对象已经构造完成。
枚举类中还有两个方法 isInitializingINITIALIZING状态时返回true isConfigured大于等于 CONFIGURING 的时候返回 true 也就是说配置器初始化完成时在构造器看来就算以配置状态了。
4.2 成员变量
private final Log logger LogFactory.getLog(getClass());private final LinkedHashMapClass? extends SecurityConfigurerO, B, ListSecurityConfigurerO, B configurers new LinkedHashMap();private final ListSecurityConfigurerO, B configurersAddedInInitializing new ArrayList();private final MapClass?, Object sharedObjects new HashMap();private final boolean allowConfigurersOfSameType;private BuildState buildState BuildState.UNBUILT;private ObjectPostProcessorObject objectPostProcessor;configurers所要应用到当前 SecurityBuilder 上的所有的 SecurityConfigurer。configurersAddedInInitializing用于记录在初始化期间添加进来的 SecurityConfigurer。sharedObjects共享对象。ObjectPostProcessor由外部调用者提供这是一个后置处理对象在创建完对象后会用到这个后置处理对象。
4.3 构造方法
/**** Creates a new instance with the provided {link ObjectPostProcessor}. This post* processor must support Object since there are many types of objects that may be* post processed.* param objectPostProcessor the {link ObjectPostProcessor} to use*/
protected AbstractConfiguredSecurityBuilder(ObjectPostProcessorObject objectPostProcessor) {this(objectPostProcessor, false);
}/**** Creates a new instance with the provided {link ObjectPostProcessor}. This post* processor must support Object since there are many types of objects that may be* post processed.* param objectPostProcessor the {link ObjectPostProcessor} to use* param allowConfigurersOfSameType if true, will not override other* {link SecurityConfigurer}s when performing apply*/
protected AbstractConfiguredSecurityBuilder(ObjectPostProcessorObject objectPostProcessor,boolean allowConfigurersOfSameType) {Assert.notNull(objectPostProcessor, objectPostProcessor cannot be null);this.objectPostProcessor objectPostProcessor;this.allowConfigurersOfSameType allowConfigurersOfSameType;
}构造函数只对两个成员变量进行了赋值 objectPostProcessor由外部调用者提供这是一个后置处理对象在创建完对象后会用到这个后置处理对象。 allowConfigurersOfSameType从源码可以看出默认情况下 allowConfigurersOfSameType 是 false 。 这个成员变量的含义: true 表示允许相同类型的构造器在应用配置器时不会覆盖相同类型的配。
4.4 方法
4.4.1 getOrBuild 方法
想要用构造器获取最终构造的对象时需调用这个方法。
这个方法的逻辑很简单调用 isUnbuilt() 方法判断对象创建状态是否未构建完成 return buildState BuildState.UNBUILT
如果对象已经创建就直接返回已经构建好的对象否则调用构造器的 build() 方法构建对象并返回已构建完成的对象。
从刚才看到的父类 AbstractSecurityBuilder 代码中可以知道真正的构建过程是调用子类 doBuild() 方法完成的。 isUnbuilt() 方法中对 configurers 成员变量加了锁synchronized保证获取到的构建完成状态时对象真的已经构建好了。 /*** Similar to {link #build()} and {link #getObject()} but checks the state to* determine if {link #build()} needs to be called first.* return the result of {link #build()} or {link #getObject()}. If an error occurs* while building, returns null.*/
public O getOrBuild() {if (!isUnbuilt()) {return getObject();}try {return build();}catch (Exception ex) {this.logger.debug(Failed to perform build. Returning null, ex);return null;}
}/*** Determines if the object is unbuilt.* return true, if unbuilt else false*/
private boolean isUnbuilt() {synchronized (this.configurers) {return this.buildState BuildState.UNBUILT;}
}4.4.2 doBuild 方法
使用以下步骤对configurers执行生成
/*** Executes the build using the {link SecurityConfigurer}s that have been applied* using the following steps:** ul* liInvokes {link #beforeInit()} for any subclass to hook into/li* liInvokes {link SecurityConfigurer#init(SecurityBuilder)} for any* {link SecurityConfigurer} that was applied to this builder./li* liInvokes {link #beforeConfigure()} for any subclass to hook into/li* liInvokes {link #performBuild()} which actually builds the Object/li* /ul*/
Override
protected final O doBuild() throws Exception {synchronized (this.configurers) {this.buildState BuildState.INITIALIZING;beforeInit();init();this.buildState BuildState.CONFIGURING;beforeConfigure();configure();this.buildState BuildState.BUILDING;O result performBuild();this.buildState BuildState.BUILT;return result;}
}构建过程对 configurers 加锁。方法体中时构建对象的整个流程包括状态变化。构建过程大致分为构建器初始化 beforeInit()、init()构建器配置 beforeConfigure()、configure()构建对象 performBuild()。 构建过程对 configurers 加锁也就意味着进入构建方法后 configurers 中的构建器应该都准备好了。这个时候如果再添加或者修改配置器都会失败。 4.4.3 beforeInit 方法 和 beforeConfigure 方法
这两个方法是抽象方法由子类实现。子类通过覆盖这两个方法可以挂钩到对象构建的生命周期中实现在配置器SecurityConfigurer调用初始化方法或者配置方法之前做用户自定义的操作。
/*** Invoked prior to invoking each {link SecurityConfigurer#init(SecurityBuilder)}* method. Subclasses may override this method to hook into the lifecycle without* using a {link SecurityConfigurer}.*/
protected void beforeInit() throws Exception {
}/*** Invoked prior to invoking each* {link SecurityConfigurer#configure(SecurityBuilder)} method. Subclasses may* override this method to hook into the lifecycle without using a* {link SecurityConfigurer}.*/
protected void beforeConfigure() throws Exception {
}4.4.4 init 方法
SuppressWarnings(unchecked)
private void init() throws Exception {CollectionSecurityConfigurerO, B configurers getConfigurers();for (SecurityConfigurerO, B configurer : configurers) {configurer.init((B) this);}for (SecurityConfigurerO, B configurer : this.configurersAddedInInitializing) {configurer.init((B) this);}
}方法很简单功能很简单就是遍历 configurers 和 configurersAddedInInitializing 对里面存储的配置器进行初始化。 配置器初始化的详细内容到看配置器源码时在了解。 4.4.5 configure 方法
SuppressWarnings(unchecked)
private void configure() throws Exception {CollectionSecurityConfigurerO, B configurers getConfigurers();for (SecurityConfigurerO, B configurer : configurers) {configurer.configure((B) this);}
}private CollectionSecurityConfigurerO, B getConfigurers() {ListSecurityConfigurerO, B result new ArrayList();for (ListSecurityConfigurerO, B configs : this.configurers.values()) {result.addAll(configs);}return result;
}遍历 configurers 调用所有配置器的 configure(SecurityBuilder b) 方法对当前的构建器this进行配置。 配置器配置详细内容到看配置器源码时在了解。 4.4.6 performBuild 方法
这也是一个抽象方法需要子类实现完成对象的创建并返回。
4.4.7 apply 方法
/*** Applies a {link SecurityConfigurerAdapter} to this {link SecurityBuilder} and* invokes {link SecurityConfigurerAdapter#setBuilder(SecurityBuilder)}.* param configurer* return the {link SecurityConfigurerAdapter} for further customizations* throws Exception*/
SuppressWarnings(unchecked)
public C extends SecurityConfigurerAdapterO, B C apply(C configurer) throws Exception {configurer.addObjectPostProcessor(this.objectPostProcessor);configurer.setBuilder((B) this);add(configurer);return configurer;
}/*** Applies a {link SecurityConfigurer} to this {link SecurityBuilder} overriding any* {link SecurityConfigurer} of the exact same class. Note that object hierarchies* are not considered.* param configurer* return the {link SecurityConfigurerAdapter} for further customizations* throws Exception*/
public C extends SecurityConfigurerO, B C apply(C configurer) throws Exception {add(configurer);return configurer;
}这个方法的作用是将 SecurityConfigurerAdapter 配置器的适配器或者 SecurityConfigurer 配置器应用到当前的构建器。这两个方法是相互重载的他们最后都调用了 add(configurer) 方法将配置器添加到构建器方便构建时使用初始配置。 关于 SecurityConfigurerAdapter 和 SecurityConfigurer 后面再详细了解。这里观察可以看出他们实现了相同的接口都可以作为add方法的参数。 而且 public C extends SecurityConfigurerAdapterO,B C apply(C configurer)throws Exception方法在6.2 版本标记为废弃。 4.4.8 add 方法
/*** Adds {link SecurityConfigurer} ensuring that it is allowed and invoking* {link SecurityConfigurer#init(SecurityBuilder)} immediately if necessary.* param configurer the {link SecurityConfigurer} to add*/
SuppressWarnings(unchecked)
private C extends SecurityConfigurerO, B void add(C configurer) {Assert.notNull(configurer, configurer cannot be null);Class? extends SecurityConfigurerO, B clazz (Class? extends SecurityConfigurerO, B) configurer.getClass();synchronized (this.configurers) {if (this.buildState.isConfigured()) {throw new IllegalStateException(Cannot apply configurer to already built object);}ListSecurityConfigurerO, B configs null;if (this.allowConfigurersOfSameType) {configs this.configurers.get(clazz);}configs (configs ! null) ? configs : new ArrayList(1);configs.add(configurer);this.configurers.put(clazz, configs);if (this.buildState.isInitializing()) {this.configurersAddedInInitializing.add(configurer);}}
}这个方法将配置器添加到一个map集合里面这个map中以配置器的类名为 Key以存放这个类型的配置器的 List 集合为 Value。 在执行添加操作时会对 configurers 加锁synchronized 。 通过构造方法中设置的 allowConfigurersOfSameType 值判断是否允许添加相同类型的配置器如果是 true 那么在添加之前会根据类名先从 map 中获取该类型配置器链表List如果获取到了就把要添加的配置器追加到后面然后把追加了新配置器的List再放回到 map 里面如果获取到 null 接创建一个新的 List 来存放配置器。 添加配置器时如果该构建器已经处于以配置状态大于等于 CONFIGURING.order 那么会抛出异常如果该构建器已经处于 INITIALIZING 状态那么久将这个适配器链表存放到 configurersAddedInInitializing 这个map中否则将适配器链表存放到 configurers 这个 map 集合中。 遗留一个问题没有看出来为什么要使用 configurersAddedInInitializing 如果没有 configurersAddedInInitializing 这个设计会出现什么并发问题吗 4.4.9 其他方法 剩下的方法都是一些getsetremove 方法很好理解不做多余追述。