文档章节

Spring框架中的设计模式(三)

瑞查德-Jack
 瑞查德-Jack
发布于 07/19 15:50
字数 1846
阅读 21
收藏 3

Spring框架中的设计模式(三)

原创: 瑞查德-Jack

在之前的两篇文章中,我们看到了一些在Spring框架中实现的设计模式。这一次我们会发现这个流行框架使用的3种新模式。

本文将从描述两个创意设计模式开始:原型和对象池。

最后我们将重点关注行为模式—>观察者。

 

本篇前传:

原型模式

这篇文章的第一个设计模式是原型。可以通过官方文档查找有关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定义。我们可以看到,在给定的例子中:

  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.它在测试结束时被修改,以证明两个引用都属于两个不同的对象。

对象池

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的原型,避免重新创建巨型对象的对象池,以及将应用程序的上下文事件分派给适当的监听器的观察者。

© 著作权归作者所有

共有 人打赏支持
瑞查德-Jack
粉丝 7
博文 17
码字总数 39808
作品 0
通州
程序员
Spring框架中的设计模式(五)

Spring框架中的设计模式(五) 通过以前的4篇文章,我们看到Spring采用了大量的关于创建和结构方面的设计模式。本文将描述属于行为方面的两种设计模式:命令和访问者。 前传: Spring框架中的...

瑞查德-Jack
07/20
0
0
Spring框架中的设计模式(四)​

Spring框架中的设计模式(四) 本文是Spring框架中使用的设计模式第四篇。本文将在此呈现出新的3种模式。一开始,我们会讨论2种结构模式:适配器和装饰器。在第三部分和最后一部分,我们将讨...

瑞查德-Jack
07/20
0
0
这些Spring中的设计模式,你都知道吗?

设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆。 Spring作为业界的经典框架,无论是在架构设计方面,还是在代码编写方面,都堪称行...

Java填坑之路
昨天
0
0
Spring IOC FactoryBean检测与获取Bean

Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean。Spring FactoryBean是创建复杂的bean,一般的bean直接用xml配置即可,如果一个bean的创建过程中涉及到很多其他的b...

哲别0
05/28
0
0
咕泡-Factory设计模式笔记

个人感悟: 设计模式都是处理复杂问题的,如果问题本身很简单,使用设计模式反而累赘,增加了开发的复杂性 遇到最简单的情况,直接 new 如果创建对象的过程简单(比如封装一些页面需要展示用...

职业搬砖20年
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JS三元运算示例

1. topFlag=topFlag ==0?1:0; 等于 if(topFlag=00){ topFlag=1; }else if(topFlag == 1){ topFlag=0; } 2. 5>3?alert('5大'):alert('3大'); 即 if(5>3){alert('5大')}else{alert('3大')}; 注......

森火
今天
0
0
利用Slf4j的MDC跟踪方法调用链

why? 一个web项目通常提供很多URL访问地址, 项目一般都是分层处理,例如Controller——>Service——>DAO。 如果想根据日志查看用户一次请求都走了哪些方法(多数是查错误)。 如果系统是多人...

杨春炼
今天
9
0
Maven介绍及安装

Maven介绍及安装 以下内容是本人早期学习时的笔记,可能比较详实繁琐,现在复习一下Maven,顺便将内容抛出来,供大家一起学习进步。 一、Maven简介 Maven是Apache旗下的一款项目管理工具,是...

星汉
今天
0
0
小程序Aes解密

主要步骤: 1、下载AES源码(JS版) 2、在小程序中新建一个公共的文件夹,把AES源码拷贝进去(注意:需要暴露接口 module.exports = CryptoJS;) 3、添加一个用于加密解密的公共JS,可取名为...

Mr_Tea伯奕
今天
0
0
Go实现文件传输(基本传输可用)

发送端 package mainimport ("fmt""os""net""io")func SendFile(path string, connect net.Conn){file, oerr :=os.Open(path)if oerr !=nil{fmt.Println("Open", oerr)......

CHONGCHEN
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部