<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          盤點 Spring Security 框架中的八大經(jīng)典設(shè)計模式

          共 8554字,需瀏覽 18分鐘

           ·

          2020-10-21 04:44


          上次有小伙伴建議,源碼分析太枯燥了,要是能夠結(jié)合設(shè)計模式一起來,這樣更有助于大家理解 Spring Security 源碼,同時還能復(fù)習(xí)一波設(shè)計模式。

          因此松哥今天就試著整一篇,和大家來聊一聊 Spring Security 中涉及到的設(shè)計模式,不過 Spring Security 中涉及到的設(shè)計模式還是非常多的,松哥這里講幾個,剩下的歡迎小伙伴們留言補充。

          1.模板方法模式

          ?

          Template Pattern(模板方法模式)是一個抽象類公開定義了執(zhí)行它的方法的模板。它的子類可以按需要重寫方法實現(xiàn),但調(diào)用將以抽象類中定義的方式進行,這是一種行為型模式。

          模板方法方式優(yōu)點如下:

          • 在父類中提取了公共的部分代碼,便于代碼復(fù)用和擴展。
          • 部分方法是由子類實現(xiàn)的,子類可以通過擴展方式增加相應(yīng)的功能,符合開閉原則。

          缺點如下:

          • 對每個不同的實現(xiàn)都需要定義一個子類,導(dǎo)致類的個數(shù)增加,系統(tǒng)更加復(fù)雜,設(shè)計也更加抽象。
          • 父類中的抽象方法由子類實現(xiàn),子類執(zhí)行的結(jié)果會影響父類的結(jié)果,增加了代碼理解難度。

          介紹完模板方法模式,大家可能大概猜到了 Spring Security 中哪些地方用到模板方法模式了。

          我舉幾個簡單的例子。

          第一個例子是 AbstractUserDetailsAuthenticationProvider 類的設(shè)計。大家都知道這個類是用來做驗證的,認(rèn)證的邏輯在這個方法中都定義好了,但是該類卻定義了兩個抽象方法:

          • retrieveUser 該方法用戶從數(shù)據(jù)源中獲取用戶對象。
          • additionalAuthenticationChecks 該方法用來做額外的校驗(登錄憑證的校驗)

          這兩個抽象方法是在 DaoAuthenticationProvider 中實現(xiàn)的。DaoAuthenticationProvider 的實現(xiàn)就是從數(shù)據(jù)庫中加載用戶,默認(rèn)檢驗登錄憑證也都是驗證密碼。

          如果你的數(shù)據(jù)源來自其他地方,或者登錄憑證不是密碼,那么自定義類繼承自 AbstractUserDetailsAuthenticationProvider 并重寫它里邊的這兩個方法即可。

          2.責(zé)任鏈模式

          ?

          Chain of Responsibility Pattern(責(zé)任鏈模式) ,在這種模式中,通常每個接收者都包含對另一個接收者的引用,如果一個對象不能處理該請求,那么它會把相同的請求傳給下一個接收者,依此類推。在這個過程中,客戶只需要將請求發(fā)送到責(zé)任鏈上即可,無須關(guān)心請求的處理細節(jié)和請求的傳遞過程,所以責(zé)任鏈將請求的發(fā)送者和請求的處理者解耦了。

          責(zé)任鏈模式優(yōu)點如下:

          • 降低對象之間的耦合度。
          • 增強了系統(tǒng)的可擴展性。
          • 當(dāng)工作流程發(fā)生變化,可以動態(tài)地改變鏈內(nèi)的成員或者調(diào)動它們的次序。
          • 簡化了對象之間的連接,每個對象只需保持一個指向其后繼者的引用,不需保持其他所有處理者的引用。
          • 責(zé)任分擔(dān),每個類只需要處理自己該處理的工作,符合類的單一職責(zé)原則。

          缺點如下:

          • 對比較長的職責(zé)鏈,請求的處理可能涉及多個處理對象,系統(tǒng)性能將受到一定影響。
          • 職責(zé)鏈建立的合理性要靠客戶端來保證,增加了客戶端的復(fù)雜性。

          很明顯,Spring Security 中的過濾器鏈就是一種責(zé)任鏈模式。一個請求到達后,被過濾器鏈中的過濾器逐個進行處理,過濾器鏈中的過濾器每個都具有不同的職能并且互不相擾,我們還可以通過 HttpSecurity 來動態(tài)配置過濾器鏈中的過濾器(即添加/刪除過濾器鏈中的過濾器)。

          具體的代碼在 FilterChainProxy$VirtualFilterChain 中,如下:

          那么接下來我們就來看看 VirtualFilterChain:

          private?static?class?VirtualFilterChain?implements?FilterChain?{
          ?private?final?FilterChain?originalChain;
          ?private?final?List?additionalFilters;
          ?private?final?FirewalledRequest?firewalledRequest;
          ?private?final?int?size;
          ?private?int?currentPosition?=?0;
          ?private?VirtualFilterChain(FirewalledRequest?firewalledRequest,
          ???FilterChain?chain,?List?additionalFilters)
          ?
          {
          ??this.originalChain?=?chain;
          ??this.additionalFilters?=?additionalFilters;
          ??this.size?=?additionalFilters.size();
          ??this.firewalledRequest?=?firewalledRequest;
          ?}
          ?@Override
          ?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. VirtualFilterChain 類中首先聲明了 5 個全局屬性,originalChain 表示原生的過濾器鏈,也就是 Web Filter;additionalFilters 表示 Spring Security 中的過濾器鏈;firewalledRequest 表示當(dāng)前請求;size 表示過濾器鏈中過濾器的個數(shù);currentPosition 則是過濾器鏈遍歷時候的下標(biāo)。
          2. doFilter 方法就是 Spring Security 中過濾器挨個執(zhí)行的過程,如果 currentPosition == size,表示過濾器鏈已經(jīng)執(zhí)行完畢,此時通過調(diào)用 originalChain.doFilter 進入到原生過濾鏈方法中,同時也退出了 Spring Security 過濾器鏈。否則就從 additionalFilters 取出 Spring Security 過濾器鏈中的一個個過濾器,挨個調(diào)用 doFilter 方法。nextFilter.doFilter 就是過濾器鏈挨個往下走。

          3.策略模式

          ?

          Strategy Pattern(策略模式),它定義了一系列算法,將每一個算法封裝起來,并讓它們可以相互替換。策略模式讓算法獨立于使用它的客戶而變化,也稱為政策模式(Policy)。

          策略模式的優(yōu)點:

          • 策略模式提供了對“開閉原則”的完美支持,用戶可以在不修改原有系統(tǒng)的基礎(chǔ)上選擇具體的策略,也可以靈活地擴展新的策略。
          • 策略模式提供了管理相關(guān)的策略的方式。
          • 策略模式提供了可以替換繼承關(guān)系的辦法。
          • 使用策略模式可以避免使用多重條件轉(zhuǎn)移語句。

          策略模式的缺點:

          • 客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。
          • 策略模式將造成產(chǎn)生很多策略類(可以通過使用享元模式在一定程度上減少對象的數(shù)量)。

          Spring Security 中使用策略模式的地方也有好幾個。

          第一個就是用戶登錄信息存儲。

          在 SecurityContextHolder 中定義登錄用戶信息存儲的方法,就定義了三種不同的策略:

          public?class?SecurityContextHolder?{
          ?//?~?Static?fields/initializers
          ?//?=====================================================================================

          ?public?static?final?String?MODE_THREADLOCAL?=?"MODE_THREADLOCAL";
          ?public?static?final?String?MODE_INHERITABLETHREADLOCAL?=?"MODE_INHERITABLETHREADLOCAL";
          ?public?static?final?String?MODE_GLOBAL?=?"MODE_GLOBAL";
          ?public?static?final?String?SYSTEM_PROPERTY?=?"spring.security.strategy";
          ?private?static?String?strategyName?=?System.getProperty(SYSTEM_PROPERTY);
          ?private?static?SecurityContextHolderStrategy?strategy;
          }

          還有一個就是 session 并發(fā)管理。

          在 AbstractAuthenticationProcessingFilter#doFilter 方法中,有如下代碼:

          public?void?doFilter(ServletRequest?req,?ServletResponse?res,?FilterChain?chain)
          ??throws?IOException,?ServletException?
          {
          ?//省略
          ??sessionStrategy.onAuthentication(authResult,?request,?response);
          ?//省略
          }

          這就是一種策略模式。


          4.代理模式

          ?

          Proxy Pattern(代理模式) :給某一個對象提供一個代理,并由代理對象控制對原對象的引用,它是一種對象結(jié)構(gòu)型模式。

          代理模式的優(yōu)點:

          • 一定程度上降低了系統(tǒng)的耦合度。
          • 代理對象可以擴展目標(biāo)對象的功能。
          • 代理對象可以保護目標(biāo)對象。

          缺點:

          • 在客戶端和真實對象之間增加了代理,可能會導(dǎo)致請求的處理速度變慢。
          • 增加了系統(tǒng)復(fù)雜度。

          代理模式在 Spring Security 中最重要的應(yīng)用就是 Spring Security 過濾器鏈接入 Web Filter 的過程,使用了 Spring 提供的 DelegatingFilterProxy,這就是一個典型的代理模式:

          public?class?DelegatingFilterProxy?extends?GenericFilterBean?{
          ?@Override
          ?public?void?doFilter(ServletRequest?request,?ServletResponse?response,?FilterChain?filterChain)
          ???throws?ServletException,?IOException?
          {

          ??//?Lazily?initialize?the?delegate?if?necessary.
          ??Filter?delegateToUse?=?this.delegate;
          ??if?(delegateToUse?==?null)?{
          ???synchronized?(this.delegateMonitor)?{
          ????delegateToUse?=?this.delegate;
          ????if?(delegateToUse?==?null)?{
          ?????WebApplicationContext?wac?=?findWebApplicationContext();
          ?????if?(wac?==?null)?{
          ??????throw?new?IllegalStateException("No?WebApplicationContext?found:?"?+
          ????????"no?ContextLoaderListener?or?DispatcherServlet?registered?");
          ?????}
          ?????delegateToUse?=?initDelegate(wac);
          ????}
          ????this.delegate?=?delegateToUse;
          ???}
          ??}

          ??//?Let?the?delegate?perform?the?actual?doFilter?operation.
          ??invokeDelegate(delegateToUse,?request,?response,?filterChain);
          ?}
          }

          當(dāng)然還有其他很多地方也用到代理模式,我就不一一列舉了,歡迎小伙伴們留言補充。

          5.適配器模式

          ?

          Adapter Pattern(適配器模式),大家平時用的手機充電器學(xué)名叫做電源適配器,它的作用是把 220V 的電壓轉(zhuǎn)為手機可用的 5V 電壓。所以適配器模式其實也是類似作用,將一個接口轉(zhuǎn)換成客戶希望的另一個接口,適配器模式使接口不兼容的類可以一起工作。適配器模式又分為類適配器模式、對象適配器模式以及接口適配器模式。

          適配器模式的優(yōu)點:

          • 解耦,通過引入一個適配器類來重用現(xiàn)有的適配者類,而無須修改原有代碼。
          • 增加了類的透明性和復(fù)用性。
          • 具有較好的靈活性和擴展性都。

          缺點:

          • 由于 Java 不支持多重繼承,一次最多只能適配一個適配者類,而且目標(biāo)抽象類只能為抽象類,不能為具體類,其使用有一定的局限性。

          Spring Security 中的適配器模式也是非常多的,例如我們最為常見的 WebSecurityConfigurerAdapter,該類讓兩個原本不相關(guān)的 WebSecurity 和 HttpSecurity 能夠在一起工作。

          6.建造者模式

          ?

          Builder Pattern(建造者模式)是將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的對象出來,用戶只需要指定復(fù)雜對象的類型和內(nèi)容就可以構(gòu)建對象,而不需要知道內(nèi)部的具體構(gòu)建細節(jié)。

          建造者模式優(yōu)點:

          • 將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品對象,而客戶端不需要知道產(chǎn)品內(nèi)部細節(jié)。
          • 每一個產(chǎn)品對應(yīng)一個建造者,用戶使用不同的建造者可以創(chuàng)建不同的產(chǎn)品,建造者本身可以輕松修改或者添加。
          • 可以更加精細地控制產(chǎn)品的創(chuàng)建過程。

          缺點:

          • 創(chuàng)建的產(chǎn)品需要有一定的相似性,如果差異過大,則不適合建造者模式。
          • 產(chǎn)品本身的復(fù)雜度會提高建造者的復(fù)雜度。

          Spring Security 中對于建造者模式的使用也是非常多,例如典型的 AuthenticationManagerBuilder,它想要建造的對象是 AuthenticationManager,對應(yīng)的建造方法則是 build。一般建造者模式中建造者類命名以 builder 結(jié)尾,而建造方法命名為 build()。

          7.觀察者模式

          ?

          Observer(觀察者模式)指多個對象間存在一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并自動更新,觀察者模式也稱為發(fā)布-訂閱模式、模型-視圖模式,它是對象行為型模式。

          觀察者模式優(yōu)點:

          • 降低了目標(biāo)與觀察者之間的耦合關(guān)系,兩者之間是抽象耦合關(guān)系。

          缺點:

          • 目標(biāo)與觀察者之間的依賴關(guān)系并沒有完全解除,而且有可能出現(xiàn)循環(huán)引用。
          • 當(dāng)觀察者對象很多時,程序執(zhí)行效率降低。

          在 Spring 框架中,觀察者模式用于實現(xiàn) ApplicationContext 的事件處理功能。Spring 為我們提供了 ApplicationEvent 類和 ApplicationListener 接口來啟用事件處理。Spring 應(yīng)用程序中的任何 Bean 實現(xiàn) ApplicationListener 接口,都會接收到 ApplicationEvent 作為事件發(fā)布者推送的消息。在這里,事件發(fā)布者是主題(Subject) 和實現(xiàn) ApplicationListener 的 Bean 的觀察者(Observer)。

          具體到 Spring Security 中,如登錄成功事件發(fā)布,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);
          }


          8.裝飾模式

          ?

          Decorator(裝飾模式)是指在不改變現(xiàn)有對象結(jié)構(gòu)的情況下,動態(tài)地給該對象增加一些額外功能的模式。

          裝飾模式的優(yōu)點:

          • 可以靈活的擴展一個類的功能。

          缺點:

          • 增加了許多子類,使程序變得很復(fù)雜。

          Spring Security 中對于裝飾模式也有許多應(yīng)用。最典型的就是一個請求在通過過濾器鏈的時候會不停的變,會不停的調(diào)整它的功能,通過裝飾模式設(shè)計出了請求的許多類,例如:

          • HeaderWriterRequest
          • FirewalledRequest
          • StrictHttpFirewall
          • SaveToSessionRequestWrapper
          • ...

          等等,類似的很多,我就不一一贅述了。

          小結(jié)

          松哥的 Spring Security 還在持續(xù)連載中,未來連載完了還會總結(jié)出更多的設(shè)計模式,這里先列出來八個和小伙伴們分享,如果小伙伴們有自己的見解,也歡迎留言補充。



          推薦閱讀:


          喜歡我可以給我設(shè)為星標(biāo)哦

          好文章,我“在看”
          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩精品免费无码中文字幕 | 色情片在线播放 | 成人国产免费 | 日韩无码影院 | 永久免费无人区一区 |