一、Builder设计模式
WebSecurity
、HttpSecurity
、AuthenticationManagerBuilder
都是框架中的构建者,把他们放到一起看看他们的共同特点:
查看AuthenticationManagerBuilder
的继承结构图:
查看HttpSecurity
的继承结构图:
查看WebSecurity
的继承结构图:
可以看出他们都有这样一条继承树:
bash
|- SecurityBuilder
|- AbstractSecurityBuilder
|- AbstractConfiguredSecurityBuilder
二、SecurityBuilder
java
/**
* Interface for building an Object
*
* @param <O> The type of the Object being built
* @author Rob Winch
* @since 3.2
*/
public interface SecurityBuilder<O> {
/**
* 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
java
/**
* 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 AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
// 标记对象是否处于创建中
private AtomicBoolean building = new AtomicBoolean();
private O object;
@Override
public 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只被创建一次。
这个类很简单:
-
定义了一个原子操作的对象,用来标记当前对象是否处于构造中
javaprivate 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)
:对象已经构造完成表示对象已经构造完成。
枚举类中还有两个方法:
-
isInitializing
:INITIALIZING
状态时返回true
-
isConfigured
:大于等于CONFIGURING
的时候返回true
也就是说配置器初始化完成时在构造器看来就算以配置状态了。
4.2 成员变量
java
private final Log logger = LogFactory.getLog(getClass());
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<>();
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<>();
private final Map<Class<?>, Object> sharedObjects = new HashMap<>();
private final boolean allowConfigurersOfSameType;
private BuildState buildState = BuildState.UNBUILT;
private ObjectPostProcessor<Object> objectPostProcessor;
configurers
:所要应用到当前SecurityBuilder
上的所有的SecurityConfigurer
。configurersAddedInInitializing
:用于记录在初始化期间添加进来的SecurityConfigurer
。sharedObjects
:共享对象。ObjectPostProcessor
:由外部调用者提供,这是一个后置处理对象,在创建完对象后会用到这个后置处理对象。
4.3 构造方法
java
/***
* 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(ObjectPostProcessor<Object> 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(ObjectPostProcessor<Object> 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
),保证获取到的构建完成状态时,对象真的已经构建好了。
java
/**
* 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
执行生成:
java
/**
* Executes the build using the {@link SecurityConfigurer}'s that have been applied
* using the following steps:
*
* <ul>
* <li>Invokes {@link #beforeInit()} for any subclass to hook into</li>
* <li>Invokes {@link SecurityConfigurer#init(SecurityBuilder)} for any
* {@link SecurityConfigurer} that was applied to this builder.</li>
* <li>Invokes {@link #beforeConfigure()} for any subclass to hook into</li>
* <li>Invokes {@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
)调用初始化方法或者配置方法之前做用户自定义的操作。
java
/**
* 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 方法
java
@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 : this.configurersAddedInInitializing) {
configurer.init((B) this);
}
}
方法很简单功能很简单,就是遍历 configurers
和 configurersAddedInInitializing
,对里面存储的配置器进行初始化。
配置器初始化的详细内容到看配置器源码时在了解。
4.4.5 configure 方法
java
@SuppressWarnings("unchecked")
private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.configure((B) this);
}
}
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;
}
遍历 configurers
,调用所有配置器的 configure(SecurityBuilder b)
方法对当前的构建器(this
)进行配置。
配置器配置详细内容到看配置器源码时在了解。
4.4.6 performBuild 方法
这也是一个抽象方法,需要子类实现,完成对象的创建并返回。
4.4.7 apply 方法
java
/**
* 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 SecurityConfigurerAdapter<O, 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 SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
add(configurer);
return configurer;
}
这个方法的作用是将 SecurityConfigurerAdapter
(配置器的适配器)或者 SecurityConfigurer
(配置器)应用到当前的构建器。这两个方法是相互重载的,他们最后都调用了 add(configurer)
方法,将配置器添加到构建器,方便构建时使用(初始,配置)。
关于
SecurityConfigurerAdapter
和SecurityConfigurer
后面再详细了解。这里观察可以看出,他们实现了相同的接口,都可以作为add
方法的参数。
而且public <C extends SecurityConfigurerAdapter<O,B>> C apply(C configurer)throws Exception
方法在6.2 版本标记为废弃。
4.4.8 add 方法
java
/**
* 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 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 (this.configurers) {
if (this.buildState.isConfigured()) {
throw new IllegalStateException("Cannot apply " + configurer + " to already built object");
}
List<SecurityConfigurer<O, 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 其他方法
剩下的方法都是一些get
,set
,remove
方法很好理解,不做多余追述。