本文介绍: `WebSecurity`、`HttpSecurity`、`AuthenticationManagerBuilder` 都是框架中的构建者,把他们放到一起看看他们的共同特点:可以看出他们都有这样一条继承树:“`bash|- SecurityBuilder |- AbstractSecurityBuilder |- AbstractConfiguredSecurityBuilder

一、Builder设计模式

WebSecurityHttpSecurityAuthenticationManagerBuilder 都是框架中的构建者,把他们放到一起看看他们的共同特点:

查看AuthenticationManagerBuilder继承结构图:

在这里插入图片描述

查看HttpSecurity继承结构图:

在这里插入图片描述
查看WebSecurity继承结构图:

在这里插入图片描述
可以看出他们都有这样一条继承树:

|- SecurityBuilder
	|- AbstractSecurityBuilder
		|- AbstractConfiguredSecurityBuilder

二、SecurityBuilder

/**
 * Interface for building an Object
 *
 * @param <O&gt; 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

/**
 * 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;

}

AbstractSecurityBuilderSecurityBuilder一个基础实现抽象类,提供构造器的基础流程控制,能够确保对象O只被创建一次

这个类很简单

四、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 方法第一次被调用,到所有 SecurityConfigurerinit 方法都被调用完这期间都是 INITIALIZING 状态

  • CONFIGURING(2)配置

    表示从所有的 SecurityConfigurerinit 方法都被调用完,直到所有 configure 方法都被调用

    意思就是所有配置器都初始化了,直到配置都被调用这段时间都时 CONFIGURING 状态

  • BUILDING(3) :对象构造中

    表示已经执行完所有的 SecurityConfigurerconfigure 方法,到刚刚执行AbstractConfiguredSecurityBuilderperformBuild 方法这期间

    意思就是从将所有配置器的配置都配置完成开始,到构造完这个对象这段时间都是 BUILDING 状态

  • BUILT(4) :对象已经构造完成

    表示对象已经构造完成。

枚举类中还有两个方法:

4.2 成员变量

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;

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

构造函数只对两个成员变量进行了赋值

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>
 * <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 加锁,也就意味着进入构建方法后 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 {
	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);
	}
}

方法很简单功能简单,就是遍历 configurersconfigurersAddedInInitializing ,对里面存储的配置器进行初始化

配置器初始化的详细内容到看配置器源码时在了解。

4.4.5 configure 方法

@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 方法

/**
 * 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) 方法,将配置器添加到构建器,方便构建时使用(初始,配置)。

关于 SecurityConfigurerAdapterSecurityConfigurer 后面再详细了解。这里观察可以看出,他们实现了相同的接口,都可以作为add方法的参数

而且 public <C extends SecurityConfigurerAdapter<O,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 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

遗留一个问题没有看出来为什么要使用 configurersAddedInInitializing ,如果没有 configurersAddedInInitializing 这个设计会出现什么并发问题吗?

4.4.9 其他方法

在这里插入图片描述

剩下的方法都是一些getsetremove 方法很好理解,不做多余追述。

原文地址:https://blog.csdn.net/ctwy291314/article/details/134712150

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_22554.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注