<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 中經(jīng)典的 9 種設計模式,打死也要記住啊!

          共 14456字,需瀏覽 29分鐘

           ·

          2023-02-10 21:43

          大家好,我是寶哥

          目錄

          • 1.簡單工廠(非23種設計模式中的一種)
          • 2.工廠方法
          • 3.單例模式
          • 4.適配器模式
          • 5.裝飾器模式
          • 6.代理模式
          • 7.觀察者模式
          • 8.策略模式
          • 9.模版方法模式



          Spring中涉及的設計模式總結(jié)



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



          實現(xiàn)方式:

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


          實質(zhì):

          由一個工廠類根據(jù)傳入的參數(shù),動態(tài)決定應該創(chuàng)建哪一個產(chǎn)品類。

          實現(xiàn)原理:

          bean容器的啟動階段:

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

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

          • 將BeanDefinition注冊到了beanFactory之后,在這里Spring為我們提供了一個擴展的切口,允許我們通過實現(xiàn)接口BeanFactoryPostProcessor 在此處來插入我們定義的代碼。

            典型的例子就是:PropertyPlaceholderConfigurer,我們一般在配置數(shù)據(jù)庫的dataSource時使用到的占位符的值,就是它注入進去的。

          容器中bean的實例化階段:

          實例化階段主要是通過反射或者CGLIB對bean進行實例化,在這個階段Spring又給我們暴露了很多的擴展點:

          • 各種的Aware接口 ,比如 BeanFactoryAware,對于實現(xiàn)了這些Aware接口的bean,在實例化bean時Spring會幫我們注入對應的BeanFactory的實例。
          • BeanPostProcessor接口 ,實現(xiàn)了BeanPostProcessor接口的bean,在實例化bean時Spring會幫我們調(diào)用接口中的方法。
          • InitializingBean接口 ,實現(xiàn)了InitializingBean接口的bean,在實例化bean時Spring會幫我們調(diào)用接口中的方法。
          • DisposableBean接口 ,實現(xiàn)了BeanPostProcessor接口的bean,在該bean死亡時Spring會幫我們調(diào)用接口中的方法。

          設計意義:

          松耦合。 可以將原來硬編碼的依賴,通過Spring這個beanFactory這個工廠來注入依賴,也就是說原來只有依賴方和被依賴方,現(xiàn)在我們引入了第三方——spring這個beanFactory,由它來解決bean之間的依賴問題,達到了松耦合的效果.

          bean的額外處理。 通過Spring接口的暴露,在實例化bean的階段我們可以進行一些額外的處理,這些額外的處理只需要讓bean實現(xiàn)對應的接口即可,那么spring就會在bean的生命周期調(diào)用我們實現(xiàn)的接口來處理該bean。[非常重要]



          2.工廠方法



          實現(xiàn)方式:

          FactoryBean接口。


          實現(xiàn)原理:

          實現(xiàn)了FactoryBean接口的bean是一類叫做factory的bean。其特點是,spring會在使用getBean()調(diào)用獲得該bean時,會自動調(diào)用該bean的getObject()方法,所以返回的不是factory這個bean,而是這個bean.getOjbect()方法的返回值。


          例子:

          典型的例子有spring與mybatis的結(jié)合。

          代碼示例:

          說明:

          我們看上面該bean,因為實現(xiàn)了FactoryBean接口,所以返回的不是 SqlSessionFactoryBean 的實例,而是它的 SqlSessionFactoryBean.getObject() 的返回值。


          3.單例模式


          • Spring依賴注入Bean實例默認是單例的。

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

          • 分析getSingleton()方法

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

          ps:spring依賴注入時,使用了 雙重判斷加鎖 的單例模式


          總結(jié)

          單例模式定義: 保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

          spring對單例的實現(xiàn): spring中的單例模式完成了后半句話,即提供了全局的訪問點BeanFactory。但沒有從構(gòu)造器級別去控制單例,這是因為spring管理的是任意的java對象。


          4.適配器模式



          實現(xiàn)方式:

          SpringMVC中的適配器HandlerAdatper。


          實現(xiàn)原理:

          HandlerAdatper根據(jù)Handler規(guī)則執(zhí)行不同的Handler。


          實現(xiàn)過程:

          DispatcherServlet根據(jù)HandlerMapping返回的handler,向HandlerAdatper發(fā)起請求,處理Handler。

          HandlerAdapter根據(jù)規(guī)則找到對應的Handler并讓其執(zhí)行,執(zhí)行完畢后Handler會向HandlerAdapter返回一個ModelAndView,最后由HandlerAdapter向DispatchServelet返回一個ModelAndView。


          實現(xiàn)意義:

          HandlerAdatper使得Handler的擴展變得容易,只需要增加一個新的Handler和一個對應的HandlerAdapter即可。

          因此Spring定義了一個適配接口,使得每一種Controller有一種對應的適配器實現(xiàn)類,讓適配器代替controller執(zhí)行相應的方法。這樣在擴展Controller時,只需要增加一個適配器類就完成了SpringMVC的擴展了。


          5.裝飾器模式



          實現(xiàn)方式:

          Spring中用到的包裝器模式在類名上有兩種表現(xiàn):一種是類名中含有Wrapper,另一種是類名中含有Decorator。


          實質(zhì):

          動態(tài)地給一個對象添加一些額外的職責。

          就增加功能來說,Decorator模式相比生成子類更為靈活。


          6.代理模式



          實現(xiàn)方式:AOP底層,就是動態(tài)代理模式的實現(xiàn)。

          • 動態(tài)代在內(nèi)存中構(gòu),不需要手動編寫代理類

          • 態(tài)代理:需要手工編寫代理類,代理類引用被代理對象。

          實現(xiàn)原理:

          切面在應用運行的時刻被織入。一般情況下,在織入切面時,AOP容器會為目標對象創(chuàng)建動態(tài)的創(chuàng)建一個代理對象。SpringAOP就是以這種方式織入切面的。

          織入:把切面應用到目標對象并創(chuàng)建新的代理對象的過程。


          7.觀察者模式


          實現(xiàn)方式:

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


          具體實現(xiàn):事件機制的實現(xiàn)需要三個部分,事件源,事件,事件監(jiān)聽器

          (1)ApplicationEvent抽象類[事件]

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

          • 該類的實現(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;
              }
          }

          (2)ApplicationListener接口[事件監(jiān)聽器]

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

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

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

          • 代碼:

          public interface ApplicationListener<E extends ApplicationEventextends EventListener {
               void onApplicationEvent(E event);
          }

          (3)ApplicationContext接口[事件源]

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

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

          • 責:負責讀取bean的配置文檔,管理bean的加載,維護bean之間的依賴關系,可以說是負責bean的整個生命周期,再通俗一點就是我們平時所說的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);
              }
          }

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

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

          • 代碼:

          public abstract class AbstractApplicationContext extends DefaultResourceLoader
              implements ConfigurableApplicationContextDisposableBean 
          {
              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.classtruefalse);
              for (String lisName : listenerBeanNames) {
              getApplicationEventMulticaster().addApplicationListenerBean(lisName);
              }
            }
          }



          8.策略模式



          實現(xiàn)方式:

          Spring框架的資源訪問Resource接口。該接口提供了更強的資源訪問能力,Spring 框架本身大量使用了 Resource 接口來訪問底層資源。


          Resource 接口介紹

          source 接口是具體資源訪問策略的抽象,也是所有資源訪問類所實現(xiàn)的接口。

          Resource 接口主要提供了如下幾個方法:

          • getInputStream(): 定位并打開資源,返回資源對應的輸入流。每次調(diào)用都返回新的輸入流。調(diào)用者必須負責關閉輸入流。
          • exists(): 返回 Resource 所指向的資源是否存在。
          • isOpen(): 返回資源文件是否打開,如果資源文件不能多次讀取,每次讀取結(jié)束應該顯式關閉,以防止資源泄漏。
          • getDescription(): 返回資源的描述信息,通常用于資源處理出錯時輸出該信息,通常是全限定文件名或?qū)嶋H URL。
          • getFile: 返回資源對應的 File 對象。
          • getURL: 返回資源對應的 URL 對象。

          最后兩個方法通常無須使用,僅在通過簡單方式訪問無法實現(xiàn)時,Resource 提供傳統(tǒng)的資源訪問的功能。

          Resource 接口本身沒有提供訪問任何底層資源的實現(xiàn)邏輯,針對不同的底層資源,Spring 將會提供不同的 Resource 實現(xiàn)類,不同的實現(xiàn)類負責不同的資源訪問邏輯。

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

          • UrlResource: 訪問網(wǎng)絡資源的實現(xiàn)類。
          • ClassPathResource: 訪問類加載路徑里資源的實現(xiàn)類。
          • FileSystemResource: 訪問文件系統(tǒng)里資源的實現(xiàn)類。
          • ServletContextResource: 訪問相對于 ServletContext 路徑里的資源的實現(xiàn)類.
          • InputStreamResource: 訪問輸入流資源的實現(xiàn)類。
          • ByteArrayResource: 訪問字節(jié)數(shù)組資源的實現(xiàn)類。

          這些 Resource 實現(xiàn)類,針對不同的的底層資源,提供了相應的資源訪問邏輯,并提供便捷的包裝,以利于客戶端程序的資源訪問。


          9.模版方法模式



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

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

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

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

          共同的方法: 所有子類都會用到的代碼

          不同的方法: 子類要覆蓋的方法,分為兩種:

          • 抽象方法:父類中的是抽象方法,子類必須覆蓋
          • 鉤子方法:父類中是一個空方法,子類繼承了默認也是空的

          注:為什么叫鉤子,子類可以通過這個鉤子(方法),控制父類,因為這個鉤子實際是父類的方法(空方法)!


          Spring模板方法模式實質(zhì):

          是模板方法模式和回調(diào)模式的結(jié)合,是Template Method不需要繼承的另一種實現(xiàn)方式。Spring幾乎所有的外接擴展都采用這種模式。


          具體實現(xiàn):

          JDBC的抽象和對Hibernate的集成,都采用了一種理念或者處理方式,那就是模板方法模式與相應的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是抽象類,不能夠獨立使用,我們每次進行數(shù)據(jù)訪問的時候都要給出一個相應的子類實現(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沒有使用繼承?

          因為這個類的方法太多,但是我們還是想用到JdbcTemplate已有的穩(wěn)定的、公用的數(shù)據(jù)庫連接,那么我們怎么辦呢?

          我們可以把變化的東西抽出來作為一個參數(shù)傳入JdbcTemplate的方法中。但是變化的東西是一段代碼,而且這段代碼會用到JdbcTemplate中的變量。怎么辦?

          那我們就用回調(diào)對象吧。在這個回調(diào)對象中定義一個操縱JdbcTemplate中變量的方法,我們?nèi)崿F(xiàn)這個方法,就把變化的東西集中到這里了。然后我們再傳入這個回調(diào)對象到JdbcTemplate,從而完成了調(diào)用。

          文章來源:http://t.csdn.cn/MxOO5

          往期推薦:

          IDEA代碼重構(gòu)小技巧(VIP典藏版)

          接了個變態(tài)需求:給定一個接口,要用戶自定義動態(tài)實現(xiàn)并上傳熱部署,怎么搞?

          SpringBoot分片上傳、斷點續(xù)傳、大文件極速秒傳功能!

          Spring Boot 使用 Sa-Token-Quick-Login 插件實現(xiàn)快速登錄認證

          真香!推薦一個超級簡單 Java 圖形驗證碼模塊

          Mybatis 使用的 9 種設計模式,真是太有用了

          切記!MySQL中order by與limit不要一起用!

          瀏覽 26
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  永久免费不收费的视频 | 国产乱伦无码高清 | 激情深爱五月天 | 久久久免费黄色视频 | 色综合天天综合成人网 |