模式简介
选举模式是随便起的一个名字,因为源码里没看到给他起名字。
它用于对一个数据项进行是否通过的表决,其中表决类可能有多个。源码中的场景主要是下面两个:Spring Security里的身份认证,Spring Security里的资源授权认证。
源码中的场景详情
Spring Security里的资源最小粒度可以到方法级别,如@PreAuthorize加在方法上,通过spring表达式判断当前登录人是否有访问权限。这里判断的核心类是accessDecisionManager,他的初始化定义在GlobalMethodSecurityConfiguration中。
AccessDecisionManager是核心接口,他的核心方法是decide,即判断是否有权限。
AbstractAccessDecisionManager是默认抽象实现,这里用了模板方法,也是源码中常见处理手段(更标准化的模板模式应用可以看OncePerRequestFilter)。抽象类里定义了一个成员voter列表,这个对象表示所有投票该登录人是否可以访问该资源的列表。
下面是他的UML图。
最下面的三个实现类中分别代表三类逻辑:
- 只要有一个voter通过就可以访问
- 所有voter都通过才可以访问
- 通过的大于不通过的就可以访问
举第一个例子,也是spring security里的默认实现
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException {
int deny = 0;
for (AccessDecisionVoter voter : getDecisionVoters()) {
int result = voter.vote(authentication, object, configAttributes);
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
return; // 一个同意就直接return了
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
break;
}
}
if (deny > 0) {
throw new AccessDeniedException(
this.messages.getMessage("AbstractAccessDecisionManager.accessDenied"
, "Access is denied"));
}
// To get this far, every AccessDecisionVoter abstained
checkAllowIfAllAbstainDecisions();
}
其他几个实现类逻辑类似。
AuthenticationManager的子类ProviderManager和上面的一个通过则通过比较像,他没有提供其他类型的选举,但是提供了其他类型的子类,包括OAuth2AuthenticationManager、委派Manager等。
实际应用
实际应用场景主要是一些组合判断。上述场景中的一个过就过和所有过才过,其实也对应了算数表达式中的||和&&。