Spring框架中的設計模式(三)

Spring框架中的設計模式(三)

原創: 瑞查德-Jackhtml

在以前的兩篇文章中,咱們看到了一些在Spring框架中實現的設計模式。這一次咱們會發現這個流行框架使用的3種新模式。java

本文將從描述兩個創意設計模式開始:原型和對象池。spring

最後咱們將重點關注行爲模式—>觀察者。數據庫

 

本篇前傳:設計模式

原型模式

這篇文章的第一個設計模式是原型。能夠經過官方文檔查找有關Spring做用域中的bean做用域的文章中介紹了相似的概念(prototype)。原型設計模式與有用相同名稱的(prototype)做用域有點類似。此設計模式容許經過複製已存在的對象來建立一個對象的實例。副本應該是真正的副本。這意味着新對象的全部屬性應與複製對象的屬性相同。若是不清楚,比一個簡單的 JUnit案例更好的說明:框架

  1. public class PrototypeTest {
    
    
    
     @Test
    
     public void test() {
    
       Robot firstRobot = new Robot("Droid#1");
    
       Robot secondRobot = (Robot) firstRobot.clone();
    
       assertTrue("Cloned robot's instance can't be the same as the"
    
         +" source robot instance",
    
         firstRobot != secondRobot);
    
       assertTrue("Cloned robot's name should be '"+firstRobot.getName()+"'"
    
         +" but was '"+secondRobot.getName()+"'",
    
         secondRobot.getName().equals(firstRobot.getName()));
    
     }
    
    
    
    }
    
    
    
    
    
    class Robot implements Cloneable {
    
     private String name;
    
    
    
     public Robot(String name) {
    
       this.name = name;
    
     }
    
    
    
     public String getName() {
    
       return this.name;
    
     }
    
    
    
     protected Object clone() throws CloneNotSupportedException {
    
       return super.clone();
    
     }
    
    }

     

     

Spring中,在org.springframework.beans.factory.support.AbstractBeanFactory中使用一種特定的原型設計模式,它將初始化 bean原型做用域。新對象基於配置文件中的bean定義。咱們能夠看到,在給定的例子中:ide

  1. <bean id="shoppingCart" class="com.waitingforcode.data.ShoppingCart" scope="prototype">
    
     <property name="id" value="9"></property>
    
    </bean>

     

    @RunWith(SpringJUnit4ClassRunner.class)
    
    @ContextConfiguration(locations={"applicationContext-test.xml"})
    
    public class SpringPrototypeTest {
    
    
    
     @Autowired
    
     private BeanFactory beanFactory;
    
    
    
     @Test
    
     public void test() {
    
       ShoppingCart cart1 = (ShoppingCart) beanFactory.getBean("shoppingCart");
    
       assertTrue("Id of cart1 should be 9 but was "+cart1.getId(),
    
         cart1.getId() == 9);
    
       cart1.setId(100);
    
       ShoppingCart cart2 = (ShoppingCart) beanFactory.getBean("shoppingCart");
    
       assertTrue("Id of cart2 should be 9 but was "+cart2.getId(),
    
         cart2.getId() == 9);
    
       assertTrue("Id of second cart ("+cart2.getId()+") shouldn't be the same as the first one: "+cart1.getId(),
    
         cart1.getId() != cart2.getId());
    
       cart2.setId(cart1.getId());
    
       assertTrue("Now (after cart2.setId(cart1.getId())), the id of second cart ("+cart2.getId()+") should be the same as the first one: "
    
         +cart1.getId(), cart1.getId() == cart2.getId());
    
       assertTrue("Both instance shouldn't be the same", cart1 != cart2);
    
     }
    
    
    
    }

     

 

從前面的例子能夠看出, ShoppingCart實例是直接從bean定義建立的。最初,cart1cart2對象的 id值爲 9.它在測試結束時被修改,以證實兩個引用都屬於兩個不一樣的對象。post

對象池

Spring中使用的另外一個模型是對象池設計模式。其主要目的在於在一個池中保存特定數量的對象,並根據須要從新使用。經過它,咱們能夠改善咱們想要使用 巨型對象的響應時間。 巨型意味着這些對象的構造須要不少時間(例如:持有數據庫鏈接的對象),最好重用已經存在的和未獲取的對象,而不是建立新對象。

Spring還使用線程池來管理其調度部分。一些示例位於org.springframework.scheduling.concurrent中。咱們檢索數據庫( SpringJDBC)項目中的對象池的想法。數據庫鏈接池不是由 Spring直接實現的,而是適用於 Spring工做方式的項目,如 C3P0JakartaCommonsDBCP鏈接池。

觀察者

這裏呈現的最後一個設計模式是觀察者。當一個或幾個課程正在等待具體事件時可使用它。觀察者模式由一個科目和觀察員名單組成。一個很好的例子就是 GUI界面,其中點擊按鈕(按鈕是主題)會引發聽衆(觀察者)啓動的一些操做(再說的直白點就是電影院一場電影這個 subject,須要 觀衆(也就是觀察者咯),電影產生的一些畫面產生的事件,好比恐怖 電影給男人女人帶來的不一樣的感官的感覺,傳播到觀察者也就是觀衆的眼裏所帶來的不同的反應,這個中間通常會添加一個 事件傳播者,在後面解釋 Spring的例子的時候會說到),例如:打開一個新頁面這個動做。能夠參考下面的例子:

  1. public class ObserverTest {
    
    
    
     @Test
    
     public void test() {
    
       Observer pageOpener = new PageOpener();
    
       Observer register = new Register();
    
       Button btn = new Button();
    
       btn.addListener(pageOpener);
    
       btn.addListener(register);
    
       btn.clickOn();
    
       assertTrue("Button should be clicked but it wasn't",
    
         btn.wasClicked());
    
       assertTrue("Page opener should be informed about click but it wasn't",
    
         pageOpener.wasInformed());
    
       assertTrue("Register should be informed about click but it wasn't",
    
         register.wasInformed());
    
     }
    
    
    
    }
    
    
    
    class Button {
    
    
    
     private boolean clicked;
    
     private List<observer> listeners;
    
    
    
     public List<observer> getListeners() {
    
       if (this.listeners == null) {
    
         this.listeners = new ArrayList<observer>();
    
       }
    
       return this.listeners;
    
     }
    
    
    
     public void addListener(Observer observer) {
    
       getListeners().add(observer);
    
     }
    
    
    
     public boolean wasClicked() {
    
       return this.clicked;
    
     }
    
    
    
     public void clickOn() {
    
       this.clicked = true;
    
       informAll();
    
     }
    
    
    
     private void informAll() {
    
       for (Observer observer : getListeners()) {
    
         observer.informAboutEvent();
    
       }
    
     }
    
    
    
    }
    
    
    
    abstract class Observer {
    
     protected boolean informed;
    
    
    
     public void informAboutEvent() {
    
       this.informed = true;
    
     }
    
    
    
     public boolean wasInformed() {
    
       return this.informed;
    
     }
    
    }
    
    
    
    class PageOpener extends Observer {
    
    
    
     @Override
    
     public void informAboutEvent() {
    
       System.out.println("Preparing download of new page");
    
       super.informAboutEvent();
    
     }
    
    
    
    }
    
    
    
    class Register extends Observer {
    
    
    
     @Override
    
     public void informAboutEvent() {
    
       System.out.println("Adding the action to register");
    
       super.informAboutEvent();
    
     }
    
    }

     

     

能夠看到,關於咱們的 Button實例點擊的事件被髮送到全部的觀察者對象。從這些對象開始下載頁面內容,第二個將在事件的信息保存在註冊表中。在 Spring中,觀察者設計模式用於將與應用程序上下文相關的事件傳輸到org.springframework.context.ApplicationListener的實現。要了解它們的實現方法,咱們來看一下 AbstractApplicationContext類(老版本的代碼,新版本的請自行對照):

  1. public abstract class AbstractApplicationContext extends DefaultResourceLoader
    
     implements ConfigurableApplicationContext, DisposableBean {
    
     /** Statically specified listeners */
    
     private Set<applicationlistener<?>> applicationListeners = new LinkedHashSet<applicationlistener<?>>();
    
    
    
     // some other fields and methods
    
     @Override
    
     public void addApplicationListener(ApplicationListener<?> listener) {
    
       if (this.applicationEventMulticaster != null) {
    
         this.applicationEventMulticaster.addApplicationListener(listener);
    
       }
    
       else {//新版本這裏直接咔嚓掉,上面的applicationEventMulticaster一旦爲空,就會報錯的
    
         this.applicationListeners.add(listener);
    
       }
    
     }
    
    
    
     /**
    
       * Return the list of statically specified ApplicationListeners.
    
       */
    
     public Collection<applicationlistener<?>> getApplicationListeners() {
    
       return this.applicationListeners;
    
     }
    
    
    
     /**
    
       * Add beans that implement ApplicationListener as listeners.
    
       * Doesn't affect other listeners, which can be added without being beans.
    
       */
    
     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);
    
       }
    
     }
    
    }

    在提供的代碼中,監聽器在內部添加到應用程序上下文類中,而且在 registerListeners()方法以後,它們被註冊到由接口org.springframework.context.event.ApplicationEventMulticaster表示的適當的事件多路廣播器(由於有不少listeners)。 EventMulticaster負責管理不一樣的 listener和向他們發佈事件。

  2. public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
    
       private Executor taskExecutor;
    
       private ErrorHandler errorHandler;
    
    
    
       public SimpleApplicationEventMulticaster() {
    
       }
    
    
    
       public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
    
           this.setBeanFactory(beanFactory);
    
       }
    
    
    
       public void setTaskExecutor(Executor taskExecutor) {
    
           this.taskExecutor = taskExecutor;
    
       }
    
    
    
       protected Executor getTaskExecutor() {
    
           return this.taskExecutor;
    
       }
    
    
    
       public void setErrorHandler(ErrorHandler errorHandler) {
    
           this.errorHandler = errorHandler;
    
       }
    
    
    
       protected ErrorHandler getErrorHandler() {
    
           return this.errorHandler;
    
       }
    
    
    
       public void multicastEvent(ApplicationEvent event) {
    
           this.multicastEvent(event, this.resolveDefaultEventType(event));
    
       }
    
       //發佈事件:經過池執行任務的方式來作併發處理,這樣就把以前的對象池模式給利用上了
    
       public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
    
           ResolvableType type = eventType != null?eventType:this.resolveDefaultEventType(event);
    
           Iterator var4 = this.getApplicationListeners(event, type).iterator();
    
    
    
           while(var4.hasNext()) {
    
               final ApplicationListener<?> listener = (ApplicationListener)var4.next();
    
               Executor executor = this.getTaskExecutor();
    
               if(executor != null) {
    
                   executor.execute(new Runnable() {
    
                       public void run() {
    
                           SimpleApplicationEventMulticaster.this.invokeListener(listener, event);
    
                       }
    
                   });
    
               } else {
    
                   this.invokeListener(listener, event);
    
               }
    
           }
    
    
    
       }
    
    ...
    
    }

    ​​​​​​​此次咱們講3種設計模式:用於在同一個調用做用域內建立 bean的原型,避免從新建立巨型對象的對象池,以及將應用程序的上下文事件分派給適當的監聽器的觀察者。

相關文章
相關標籤/搜索