1 | 松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->Spring Boot+Vue+微人事视频教程 上次有小伙伴建议,源码分析太枯燥了,要是能够结合设计模式一起来,这样更有助于大家理。.. |
1 | 松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->Spring Boot+Vue+微人事视频教程 |
上次有小伙伴建议,源码分析太枯燥了,要是能够结合设计模式一起来,这样更有助于大家理解 Spring Security 源码,同时还能复习一波设计模式。
因此松哥今天就试着整一篇,和大家来聊一聊 Spring Security 中涉及到的设计模式,不过 Spring Security 中涉及到的设计模式还是非常多的,松哥这里讲几个,剩下的欢迎小伙伴们留言补充。
1.模板方法模式
模板方法方式优点如下:
在父类中提取了公共的部分代码,便于代码复用和扩展。
部分方法是由子类实现的,子类可以通过扩展方式增加相应的功能,符合开闭原则。
缺点如下:
对每个不同的实现都需要定义一个子类,导致类的个数增加,系统更加复杂,设计也更加抽象。
父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,增加了代码理解难度。
介绍完模板方法模式,大家可能大概猜到了 Spring Security 中哪些地方用到模板方法模式了。
我举几个简单的例子。
第一个例子是 AbstractUserDetailsAuthenticationProvider 类的设计。大家都知道这个类是用来做验证的,认证的逻辑在这个方法中都定义好了,但是该类却定义了两个抽象方法:
retrieveUser 该方法用户从数据源中获取用户对象。
additionalAuthenticationChecks 该方法用来做额外的校验(登录凭证的校验)
这两个抽象方法是在 DaoAuthenticationProvider 中实现的。DaoAuthenticationProvider 的实现就是从数据库中加载用户,默认检验登录凭证也都是验证密码。
如果你的数据源来自其他地方,或者登录凭证不是密码,那么自定义类继承自 AbstractUserDetailsAuthenticationProvider 并重写它里边的这两个方法即可。
2.责任链模式
责任链模式优点如下:
降低对象之间的耦合度。
增强了系统的可扩展性。
当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序。
简化了对象之间的连接,每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用。
责任分担,每个类只需要处理自己该处理的工作,符合类的单一职责原则。
缺点如下:
对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性。
很明显,Spring Security 中的过滤器链就是一种责任链模式。一个请求到达后,被过滤器链中的过滤器逐个进行处理,过滤器链中的过滤器每个都具有不同的职能并且互不相扰,我们还可以通过 HttpSecurity 来动态配置过滤器链中的过滤器(即添加/删除过滤器链中的过滤器)。
具体的代码在 FilterChainProxy$VirtualFilterChain 中,如下:
那么接下来我们就来看看 VirtualFilterChain:
1 | private static class VirtualFilterChain implements FilterChain { private final FilterChain originalChain; private final List<Filter> additionalFilters; private final FirewalledRequest firewalledRequest; private final int size; private int currentPosition = 0; private VirtualFilterChain(FirewalledRequest firewalledRequest, FilterChain chain, List<Filter> additionalFilters) { this.originalChain = chain; this.additionalFilters = additionalFilters; this.size = additionalFilters.size(); this.firewalledRequest = firewalledRequest; } public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if (currentPosition == size) { if (logger.isDebugEnabled()) { logger.debug(UrlUtils.buildRequestUrl(firewalledRequest) + " reached end of additional filter chain; proceeding with original chain"); } // Deactivate path stripping as we exit the security filter chain this.firewalledRequest.reset(); originalChain.doFilter(request, response); } else { currentPosition++; Filter nextFilter = additionalFilters.get(currentPosition - 1); if (logger.isDebugEnabled()) { logger.debug(UrlUtils.buildRequestUrl(firewalledRequest) + " at position " + currentPosition + " of " + size + " in additional filter chain; firing Filter: '" + nextFilter.getClass().getSimpleName() + "'"); } nextFilter.doFilter(request, response, this); } }} |
1 | 用户可以自行选择使用哪一种策略!具体参见:在 Spring Security 中,我就想从子线程获取用户登录信息,怎么办? |
当然还有其他很多地方也用到代理模式,我就不一一列举了,欢迎小伙伴们留言补充。
#### 5.适配器模式
适配器模式的优点:
解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
增加了类的透明性和复用性。
具有较好的灵活性和扩展性都。
缺点:
由于 Java 不支持多重继承,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性。
Spring Security 中的适配器模式也是非常多的,例如我们最为常见的 WebSecurityConfigurerAdapter,该类让两个原本不相关的 WebSecurity 和 HttpSecurity 能够在一起工作。
具体参见:深入理解 WebSecurityConfigurerAdapter【源码篇】
#### 6.建造者模式
建造者模式优点:
将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象,而客户端不需要知道产品内部细节。
每一个产品对应一个建造者,用户使用不同的建造者可以创建不同的产品,建造者本身可以轻松修改或者添加。
可以更加精细地控制产品的创建过程。
缺点:
创建的产品需要有一定的相似性,如果差异过大,则不适合建造者模式。
产品本身的复杂度会提高建造者的复杂度。
Spring Security 中对于建造者模式的使用也是非常多,例如典型的 AuthenticationManagerBuilder,它想要建造的对象是 AuthenticationManager,对应的建造方法则是 build。一般建造者模式中建造者类命名以 builder 结尾,而建造方法命名为 build()。
关于 AuthenticationManagerBuilder,参见:深入理解 AuthenticationManagerBuilder 【源码篇】 一文。
#### 7.观察者模式
观察者模式优点:
降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
缺点:
目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
当观察者对象很多时,程序执行效率降低。
在 Spring 框架中,观察者模式用于实现 ApplicationContext 的事件处理功能。Spring 为我们提供了 ApplicationEvent 类和 ApplicationListener 接口来启用事件处理。Spring 应用程序中的任何 Bean 实现 ApplicationListener 接口,都会接收到 ApplicationEvent 作为事件发布者推送的消息。在这里,事件发布者是主题(Subject) 和实现 ApplicationListener 的 Bean 的观察者(Observer)。
具体到 Spring Security 中,如登录成功事件发布,session 销毁事件等等,都算是观察者模式。
例如 AbstractAuthenticationProcessingFilter#successfulAuthentication 方法:
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { if (logger.isDebugEnabled()) { logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult); } SecurityContextHolder.getContext().setAuthentication(authResult); rememberMeServices.loginSuccess(request, response, authResult); // Fire event if (this.eventPublisher != null) { eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent( authResult, this.getClass())); } successHandler.onAuthenticationSuccess(request, response, authResult);}
类似还有很多,如 session 销毁事件等(参见Spring Security 自动踢掉前一个登录用户,一个配置搞定!),我这里就不一一列举了。
8.装饰模式
装饰模式的优点:
可以灵活的扩展一个类的功能。
缺点:
增加了许多子类,使程序变得很复杂。
Spring Security 中对于装饰模式也有许多应用。最典型的就是一个请求在通过过滤器链的时候会不停的变,会不停的调整它的功能,通过装饰模式设计出了请求的许多类,例如:
HeaderWriterRequest
FirewalledRequest
StrictHttpFirewall
SaveToSessionRequestWrapper
...
等等,类似的很多,我就不一一赘述了。
一、总结
1.1 小结
松哥的 Spring Security 还在持续连载中,未来连载完了还会总结出更多的设计模式,这里先列出来八个和小伙伴们分享,如果小伙伴们有自己的见解,也欢迎留言补充。

刚刚发表
查看:
66666
回复:666
本文标题: 盘点SpringSecurity框架中的
发布时间: 2022年02月08日 00:00
最后更新: 2025年12月30日 08:54
原始链接: https://haoxiang.eu.org/500c19dc/
版权声明: 本文著作权归作者所有,均采用CC BY-NC-SA 4.0许可协议,转载请注明出处!

