<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中涉及的設(shè)計(jì)模式總結(jié)

          共 9795字,需瀏覽 20分鐘

           ·

          2021-02-17 16:16

          不點(diǎn)藍(lán)字,我們哪來故事?

          每天 11 點(diǎn)更新文章,餓了點(diǎn)外賣,點(diǎn)擊 ??《無門檻外賣優(yōu)惠券,每天免費(fèi)領(lǐng)!》


          Spring中涉及的設(shè)計(jì)模式總結(jié)

          1.簡單工廠(非23種設(shè)計(jì)模式中的一種)

          • 實(shí)現(xiàn)方式:BeanFactory。Spring中的BeanFactory就是簡單工廠模式的體現(xiàn),根據(jù)傳入一個(gè)唯一的標(biāo)識來獲得Bean對象,但是否是在傳入?yún)?shù)后創(chuàng)建還是傳入?yún)?shù)前創(chuàng)建這個(gè)要根據(jù)具體情況來定。

          • 實(shí)質(zhì):由一個(gè)工廠類根據(jù)傳入的參數(shù),動態(tài)決定應(yīng)該創(chuàng)建哪一個(gè)產(chǎn)品類。

          • 實(shí)現(xiàn)原理:

            • bean容器的啟動階段:????

              • 讀取bean的xml配置文件,將bean元素分別轉(zhuǎn)換成一個(gè)BeanDefinition對象。

              • 后通過BeanDefinitionRegistry將這些bean注冊到beanFactory中,保存在它的一個(gè)ConcurrentHashMap中。

              • 將BeanDefinition注冊到了beanFactory之后,在這里Spring為我們提供了一個(gè)擴(kuò)展的切口,允許我們通過實(shí)現(xiàn)接口BeanFactoryPostProcessor 在此處來插入我們定義的代碼。典型的例子就是:PropertyPlaceholderConfigurer,我們一般在配置數(shù)據(jù)庫的dataSource時(shí)使用到的占位符的值,就是它注入進(jìn)去的。

            • 容器中bean的實(shí)例化階段:

            實(shí)例化階段主要是通過反射或者CGLIB對bean進(jìn)行實(shí)例化,在這個(gè)階段Spring又給我們暴露了很多的擴(kuò)展點(diǎn):

              • 各種的Aware接口,比如 BeanFactoryAware,對于實(shí)現(xiàn)了這些Aware接口的bean,在實(shí)例化bean時(shí)Spring會幫我們注入對應(yīng)的BeanFactory的實(shí)例。

              • BeanPostProcessor接口,實(shí)現(xiàn)了BeanPostProcessor接口的bean,在實(shí)例化bean時(shí)Spring會幫我們調(diào)用接口中的方法。

              • InitializingBean接口,實(shí)現(xiàn)了InitializingBean接口的bean,在實(shí)例化bean時(shí)Spring會幫我們調(diào)用接口中的方法。

              • DisposableBean接口,實(shí)現(xiàn)了BeanPostProcessor接口的bean,在該bean死亡時(shí)Spring會幫我們調(diào)用接口中的方法。????

          • 設(shè)計(jì)意義:

            • 松耦合。可以將原來硬編碼的依賴,通過Spring這個(gè)beanFactory這個(gè)工長來注入依賴,也就是說原來只有依賴方和被依賴方,現(xiàn)在我們引入了第三方——spring這個(gè)beanFactory,由它來解決bean之間的依賴問題,達(dá)到了松耦合的效果.
            • bean的額外處理。通過Spring接口的暴露,在實(shí)例化bean的階段我們可以進(jìn)行一些額外的處理,這些額外的處理只需要讓bean實(shí)現(xiàn)對應(yīng)的接口即可,那么spring就會在bean的生命周期調(diào)用我們實(shí)現(xiàn)的接口來處理該bean。[非常重要]

          2.工廠方法

          • 實(shí)現(xiàn)方式:FactoryBean接口。
          • 實(shí)現(xiàn)原理:實(shí)現(xiàn)了FactoryBean接口的bean是一類叫做factory的bean。其特點(diǎn)是,spring會在使用getBean()調(diào)用獲得該bean時(shí),會自動調(diào)用該bean的getObject()方法,所以返回的不是factory這個(gè)bean,而是這個(gè)bean.getOjbect()方法的返回值。
          • 例子:
            • 典型的例子有spring與mybatis的結(jié)合。
            • 代碼示例

          微信8.0之后,又悄悄上線新功能:別人“搶不到”的紅包!趕緊看看灰度到你了沒?

          • 說明:我們看上面該bean,因?yàn)閷?shí)現(xiàn)了FactoryBean接口,所以返回的不是 SqlSessionFactoryBean 的實(shí)例,而是她的 SqlSessionFactoryBean.getObject() 的返回值。

          3.單例模式

          • Spring依賴注入Bean實(shí)例默認(rèn)是單例的。

          • Spring的依賴注入(包括lazy-init方式)都是發(fā)生在AbstractBeanFactory的getBean里。getBean的doGetBean方法調(diào)用getSingleton進(jìn)行bean的創(chuàng)建。

          • 分析getSingleton()方法

            public?Object?getSingleton(String?beanName){
            ????//參數(shù)true設(shè)置標(biāo)識允許早期依賴
            ????return?getSingleton(beanName,true);
            }
            protected?Object?getSingleton(String?beanName,?boolean?allowEarlyReference)?{
            ????//檢查緩存中是否存在實(shí)例
            ????Object?singletonObject?=?this.singletonObjects.get(beanName);
            ????if?(singletonObject?==?null?&&?isSingletonCurrentlyInCreation(beanName))?{
            ????????//如果為空,則鎖定全局變量并進(jìn)行處理。
            ????????synchronized?(this.singletonObjects)?{
            ????????????//如果此bean正在加載,則不處理
            ????????????singletonObject?=?this.earlySingletonObjects.get(beanName);
            ????????????if?(singletonObject?==?null?&&?allowEarlyReference)?{??
            ????????????????//當(dāng)某些方法需要提前初始化的時(shí)候則會調(diào)用addSingleFactory?方法將對應(yīng)的ObjectFactory初始化策略存儲在singletonFactories
            ????????????????ObjectFactory?singletonFactory?=?this.singletonFactories.get(beanName);
            ????????????????if?(singletonFactory?!=?null)?{
            ????????????????????//調(diào)用預(yù)先設(shè)定的getObject方法
            ????????????????????singletonObject?=?singletonFactory.getObject();
            ????????????????????//記錄在緩存中,earlysingletonObjects和singletonFactories互斥
            ????????????????????this.earlySingletonObjects.put(beanName,?singletonObject);
            ????????????????????this.singletonFactories.remove(beanName);
            ????????????????}
            ????????????}
            ????????}
            ????}
            ????return?(singletonObject?!=?NULL_OBJECT???singletonObject?:?null);
            }


          • getSingleton()過程圖 ps:spring依賴注入時(shí),使用了?雙重判斷加鎖?的單例模式

          我以為的周末 vs 實(shí)際上的周末

            • 總結(jié)
            • 單例模式定義:保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
            • spring對單例的實(shí)現(xiàn):spring中的單例模式完成了后半句話,即提供了全局的訪問點(diǎn)BeanFactory。但沒有從構(gòu)造器級別去控制單例,這是因?yàn)閟pring管理的是任意的java對象。

          4. 適配器模式

          • 實(shí)現(xiàn)方式:SpringMVC中的適配器HandlerAdatper。
          • 實(shí)現(xiàn)原理:HandlerAdatper根據(jù)Handler規(guī)則執(zhí)行不同的Handler。
          • 實(shí)現(xiàn)過程:DispatcherServlet根據(jù)HandlerMapping返回的handler,向HandlerAdatper發(fā)起請求,處理Handler。HandlerAdapter根據(jù)規(guī)則找到對應(yīng)的Handler并讓其執(zhí)行,執(zhí)行完畢后Handler會向HandlerAdapter返回一個(gè)ModelAndView,最后由HandlerAdapter向DispatchServelet返回一個(gè)ModelAndView。
          • 實(shí)現(xiàn)意義:HandlerAdatper使得Handler的擴(kuò)展變得容易,只需要增加一個(gè)新的Handler和一個(gè)對應(yīng)的HandlerAdapter即可。因此Spring定義了一個(gè)適配接口,使得每一種Controller有一種對應(yīng)的適配器實(shí)現(xiàn)類,讓適配器代替controller執(zhí)行相應(yīng)的方法。這樣在擴(kuò)展Controller時(shí),只需要增加一個(gè)適配器類就完成了SpringMVC的擴(kuò)展了。

          5.裝飾器模式

          • 實(shí)現(xiàn)方式:Spring中用到的包裝器模式在類名上有兩種表現(xiàn):一種是類名中含有Wrapper,另一種是類名中含有Decorator。
          • 實(shí)質(zhì):
            • 動態(tài)地給一個(gè)對象添加一些額外的職責(zé)。
            • 就增加功能來說,Decorator模式相比生成子類更為靈活。

          6.代理模式

          • 實(shí)現(xiàn)方式:AOP底層,就是動態(tài)代理模式的實(shí)現(xiàn)。
            • 動態(tài)代理:在內(nèi)存中構(gòu)建的,不需要手動編寫代理類
            • 靜態(tài)代理:需要手工編寫代理類,代理類引用被代理對象。
          • 實(shí)現(xiàn)原理:切面在應(yīng)用運(yùn)行的時(shí)刻被織入。一般情況下,在織入切面時(shí),AOP容器會為目標(biāo)對象創(chuàng)建動態(tài)的創(chuàng)建一個(gè)代理對象。SpringAOP就是以這種方式織入切面的。?織入:把切面應(yīng)用到目標(biāo)對象并創(chuàng)建新的代理對象的過程。

          7.觀察者模式

          • 實(shí)現(xiàn)方式:spring的事件驅(qū)動模型使用的是?觀察者模式?,Spring中Observer模式常用的地方是listener的實(shí)現(xiàn)。

          • 具體實(shí)現(xiàn):?事件機(jī)制的實(shí)現(xiàn)需要三個(gè)部分,事件源,事件,事件監(jiān)聽器

            • ApplicationEvent抽象類事件

              • 繼承自jdk的EventObject,所有的事件都需要繼承ApplicationEvent,并且通過構(gòu)造器參數(shù)source得到事件源.

              • 該類的實(shí)現(xiàn)類ApplicationContextEvent表示ApplicaitonContext的容器事件.

              • 代碼:

                public?abstract?class?ApplicationEvent?extends?EventObject?{
                ????private?static?final?long?serialVersionUID?=?7099057708183571937L;
                ????private?final?long?timestamp;
                ????public?ApplicationEvent(Object?source)?{
                ????super(source);
                ????this.timestamp?=?System.currentTimeMillis();
                ????}
                ????public?final?long?getTimestamp()?{
                ????????return?this.timestamp;
                ????}
                }


            • ApplicationListener接口事件監(jiān)聽器

              • 繼承自jdk的EventListener,所有的監(jiān)聽器都要實(shí)現(xiàn)這個(gè)接口。

              • 這個(gè)接口只有一個(gè)onApplicationEvent()方法,該方法接受一個(gè)ApplicationEvent或其子類對象作為參數(shù),在方法體中,可以通過不同對Event類的判斷來進(jìn)行相應(yīng)的處理。

              • 當(dāng)事件觸發(fā)時(shí)所有的監(jiān)聽器都會收到消息。

              • 代碼:

                ????public?interface?ApplicationListener<E?extends?ApplicationEvent>?extends????????????????EventListener?{
                ?????????????????void?onApplicationEvent(E?event);
                }?


            • ApplicationContext接口事件源

              • ApplicationContext是spring中的全局容器,翻譯過來是”應(yīng)用上下文”。

              • 實(shí)現(xiàn)了ApplicationEventPublisher接口。

              • 職責(zé):負(fù)責(zé)讀取bean的配置文檔,管理bean的加載,維護(hù)bean之間的依賴關(guān)系,可以說是負(fù)責(zé)bean的整個(gè)生命周期,再通俗一點(diǎn)就是我們平時(shí)所說的IOC容器。

              • 代碼:

                public?interface?ApplicationEventPublisher?{
                ????????void?publishEvent(ApplicationEvent?event);
                }???

                public?void?publishEvent(ApplicationEvent?event)?{
                ????Assert.notNull(event,?"Event?must?not?be?null");
                ????if?(logger.isTraceEnabled())?{
                ?????????logger.trace("Publishing?event?in?"?+?getDisplayName()?+?":?"?+?event);
                ????}
                ????getApplicationEventMulticaster().multicastEvent(event);
                ????if?(this.parent?!=?null)?{
                ????this.parent.publishEvent(event);
                ????}
                }

            • ApplicationEventMulticaster抽象類事件源中publishEvent方法需要調(diào)用其方法getApplicationEventMulticaster

              • 屬于事件廣播器,它的作用是把Applicationcontext發(fā)布的Event廣播給所有的監(jiān)聽器.
              • 代碼

                public?abstract?class?AbstractApplicationContext?extends?DefaultResourceLoader
                ????implements?ConfigurableApplicationContext,?DisposableBean?
                {??
                ????private?ApplicationEventMulticaster?applicationEventMulticaster;??
                ????protected?void?registerListeners()?{??
                ????//?Register?statically?specified?listeners?first.??
                ????for?(ApplicationListener?listener?:?getApplicationListeners())?{??
                ????getApplicationEventMulticaster().addApplicationListener(listener);??
                ????}??
                ????//?Do?not?initialize?FactoryBeans?here:?We?need?to?leave?all?regular?beans??
                ????//?uninitialized?to?let?post-processors?apply?to?them!??
                ????String[]?listenerBeanNames?=?getBeanNamesForType(ApplicationListener.class,?true,?false);??
                ????for?(String?lisName?:?listenerBeanNames)?{??
                ????getApplicationEventMulticaster().addApplicationListenerBean(lisName);??
                ????}??
                ??}??
                }

          8.策略模式

          • 實(shí)現(xiàn)方式:Spring框架的資源訪問Resource接口?。該接口提供了更強(qiáng)的資源訪問能力,Spring 框架本身大量使用了 Resource 接口來訪問底層資源。
          • Resource 接口介紹
            • source 接口是具體資源訪問策略的抽象,也是所有資源訪問類所實(shí)現(xiàn)的接口。
            • Resource 接口主要提供了如下幾個(gè)方法:
              • getInputStream():定位并打開資源,返回資源對應(yīng)的輸入流。每次調(diào)用都返回新的輸入流。調(diào)用者必須負(fù)責(zé)關(guān)閉輸入流。
              • exists():返回 Resource 所指向的資源是否存在。
              • isOpen():返回資源文件是否打開,如果資源文件不能多次讀取,每次讀取結(jié)束應(yīng)該顯式關(guān)閉,以防止資源泄漏。
              • getDescription():返回資源的描述信息,通常用于資源處理出錯時(shí)輸出該信息,通常是全限定文件名或?qū)嶋H URL。
              • getFile:返回資源對應(yīng)的 File 對象。
              • getURL:返回資源對應(yīng)的 URL 對象。?最后兩個(gè)方法通常無須使用,僅在通過簡單方式訪問無法實(shí)現(xiàn)時(shí),Resource 提供傳統(tǒng)的資源訪問的功能。
            • Resource 接口本身沒有提供訪問任何底層資源的實(shí)現(xiàn)邏輯,針對不同的底層資源,Spring 將會提供不同的 Resource 實(shí)現(xiàn)類,不同的實(shí)現(xiàn)類負(fù)責(zé)不同的資源訪問邏輯。

            • Spring 為 Resource 接口提供了如下實(shí)現(xiàn)類:

              • UrlResource:訪問網(wǎng)絡(luò)資源的實(shí)現(xiàn)類。
              • ClassPathResource:訪問類加載路徑里資源的實(shí)現(xiàn)類。
              • FileSystemResource:訪問文件系統(tǒng)里資源的實(shí)現(xiàn)類。
              • ServletContextResource:訪問相對于 ServletContext 路徑里的資源的實(shí)現(xiàn)類.
              • InputStreamResource:訪問輸入流資源的實(shí)現(xiàn)類。
              • ByteArrayResource:訪問字節(jié)數(shù)組資源的實(shí)現(xiàn)類。?這些 Resource 實(shí)現(xiàn)類,針對不同的的底層資源,提供了相應(yīng)的資源訪問邏輯,并提供便捷的包裝,以利于客戶端程序的資源訪問。

          9.模版方法模式

          • 經(jīng)典模板方法定義:

            • 父類定義了骨架(調(diào)用哪些方法及順序),某些特定方法由子類實(shí)現(xiàn)

            • 最大的好處:代碼復(fù)用,減少重復(fù)代碼。除了子類要實(shí)現(xiàn)的特定方法,其他方法及方法調(diào)用順序都在父類中預(yù)先寫好了。

            • 所以父類模板方法中有兩類方法:

              • 共同的方法:所有子類都會用到的代碼
              • 不同的方法:子類要覆蓋的方法,分為兩種:
                • 抽象方法:父類中的是抽象方法,子類必須覆蓋
                • 鉤子方法:父類中是一個(gè)空方法,子類繼承了默認(rèn)也是空的?注:為什么叫鉤子,子類可以通過這個(gè)鉤子(方法),控制父類,因?yàn)檫@個(gè)鉤子實(shí)際是父類的方法(空方法)!
          • Spring模板方法模式實(shí)質(zhì):?是模板方法模式和回調(diào)模式的結(jié)合,是Template Method不需要繼承的另一種實(shí)現(xiàn)方式。Spring幾乎所有的外接擴(kuò)展都采用這種模式。

          • 具體實(shí)現(xiàn):JDBC的抽象和對Hibernate的集成,都采用了一種理念或者處理方式,那就是模板方法模式與相應(yīng)的Callback接口相結(jié)合。

          • 采用模板方法模式是為了以一種統(tǒng)一而集中的方式來處理資源的獲取和釋放,以JdbcTempalte為例:

            public?abstract?class?JdbcTemplate?{??
            ?????public?final?Object?execute(String?sql){??
            ????????Connection?con=null;??
            ????????Statement?stmt=null;??
            ????????try{??
            ????????????con=getConnection();??
            ????????????stmt=con.createStatement();??
            ????????????Object?retValue=executeWithStatement(stmt,sql);??
            ????????????return?retValue;??
            ????????}catch(SQLException?e){??
            ?????????????...??
            ????????}finally{??
            ????????????closeStatement(stmt);??
            ????????????releaseConnection(con);??
            ????????}??
            ????}???
            ????protected?abstract?Object?executeWithStatement(Statement???stmt,?String?sql);??
            }??

          • 引入回調(diào)原因:

            • JdbcTemplate是抽象類,不能夠獨(dú)立使用,我們每次進(jìn)行數(shù)據(jù)訪問的時(shí)候都要給出一個(gè)相應(yīng)的子類實(shí)現(xiàn),這樣肯定不方便,所以就引入了回調(diào) 。

            • 回調(diào)代碼

              public?interface?StatementCallback{??
              ????Object?doWithStatement(Statement?stmt);??
              }???

            • 利用回調(diào)方法重寫JdbcTemplate方法

              public?class?JdbcTemplate?{??
              ????public?final?Object?execute(StatementCallback?callback){??
              ????????Connection?con=null;??
              ????????Statement?stmt=null;??
              ????????try{??
              ????????????con=getConnection();??
              ????????????stmt=con.createStatement();??
              ????????????Object?retValue=callback.doWithStatement(stmt);??
              ????????????return?retValue;??
              ????????}catch(SQLException?e){??
              ????????????...??
              ????????}finally{??
              ????????????closeStatement(stmt);??
              ????????????releaseConnection(con);??
              ????????}??
              ????}??

              ????...//其它方法定義??
              }???

            • Jdbc使用方法如下:

              JdbcTemplate?jdbcTemplate=...;??
              ????final?String?sql=...;??
              ????StatementCallback?callback=new?StatementCallback(){??
              ????public?Object=doWithStatement(Statement?stmt){??
              ????????return?...;??
              ????}??
              }????
              jdbcTemplate.execute(callback);??

          • 為什么JdbcTemplate沒有使用繼承?因?yàn)檫@個(gè)類的方法太多,但是我們還是想用到JdbcTemplate已有的穩(wěn)定的、公用的數(shù)據(jù)庫連接,那么我們怎么辦呢?我們可以把變化的東西抽出來作為一個(gè)參數(shù)傳入JdbcTemplate的方法中。但是變化的東西是一段代碼,而且這段代碼會用到JdbcTemplate中的變量。怎么辦?那我們就用回調(diào)對象吧。在這個(gè)回調(diào)對象中定義一個(gè)操縱JdbcTemplate中變量的方法,我們?nèi)?shí)現(xiàn)這個(gè)方法,就把變化的東西集中到這里了。然后我們再傳入這個(gè)回調(diào)對象到JdbcTemplate,從而完成了調(diào)用。





          往期推薦

          程序員專屬壁紙,騷氣十足!

          ArrayList的多線程場景,如何避坑?

          為何前后端總是爭吵不斷,來源于這 5 宗罪

          棄坑 FastJson,不香了



          下方二維碼關(guān)注我

          技術(shù)草根,堅(jiān)持分享?編程,算法,架構(gòu)

          看完文章,餓了點(diǎn)外賣,點(diǎn)擊 ??《無門檻外賣優(yōu)惠券,每天免費(fèi)領(lǐng)!》

          朋友,助攻一把!點(diǎn)個(gè)在看!
          瀏覽 49
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  亚洲高清无码视频在线观看 | 插吧插吧综合网 | 久热在这里只有精品66 | 12——13女人毛片毛片 | 国产黄片一区二区三区 |