Nivelle 开拓视野冲破艰险看见世界 身临其境贴近彼此感受生活

spring之事件

2017-05-14


事件驱动模型简介

事件驱动模型也就是我们常说的观察者,或者发布-订阅模型;理解它有几个关键点:

  • 一种对象间的一对多的关系;
  • 当目标发送改变(发布),观察者(订阅者)就可以接收到改变
  • 观察者如何处理,目标无需干涉;所以就松散耦合了它们之间的关系.

image

触发事件的对象称为事件发送者,接收事件的对象称为事件接收者.事件模型一半用到了如上观察者模式.

  • Subject:主题接口,即可观察者Observable,对象使用此接口注册为观察者,或者把自己从观察者中删除,每个主题可以有多个观察者。
  • Observer:有潜在的观察者必须实现观察者接口,这个接口只有update方法,当主题改变时,它被调用。
  • ConcreteSubject:具体观察者可以是任何实现了Observer接口的类。观察者必须注册具体主题,一边接收更新。
  • ConcreteObserver:一个具体主题实现了主题接口,除了注册和撤销之外,具体主题还实现了notifyObservers()方法,这个方法用来在主题状态改变时更新所有观察者。具体主题也可能有设置和获取状态的方法。
public interface Observer
{
    public void update(float temprature);
}

public class ConcreteObserver implements Observer
{
    private float temperature;
    private final Subject subject;

    public ConcreteObserver(final Subject subject)
    {
        this.subject = subject;
        this.subject.registerObserver(this);
    }

    public float getTemperature()
    {
        return temperature;
    }

    public void setTemperature(final float temperature)
    {
        this.temperature = temperature;
    }

    @Override
    public void update(final float temperature)
    {
        this.temperature = temperature;
    }
}

public interface Subject
{
    public void registerObserver(Observer o);

    public void removeObserver(Observer o);

    public void notifyObservers();

}

public class ConcreteSubject implements Subject
{
    private final List<Observer> observers;
    private float temperature;

    public float getTemperature()
    {
        return temperature;
    }

    private void temperatureChanged()
    {
        this.notifyObservers();
    }

    public void setTemperature(final float temperature)
    {
        this.temperature = temperature;
        this.temperatureChanged();
    }

    public ConcreteSubject()
    {
        observers = new ArrayList<Observer>();
    }

    @Override
    public void registerObserver(final Observer o)
    {
        observers.add(o);
    }

    @Override
    public void removeObserver(final Observer o)
    {
        if (observers.indexOf(o) >= 0)
        {
            observers.remove(o);
        }
    }

    @Override
    public void notifyObservers()
    {
        for (final Observer o : observers)
        {
            o.update(temperature);
        }
    }
}

public class Client
{
    public static void main(final String[] args)
    {
        final ConcreteSubject sb = new ConcreteSubject();
        sb.setTemperature((float) 20.00);

        final Observer o = new ConcreteObserver(sb);
        sb.setTemperature((float) 21.00);

    }
}


观察者模式的应用场景:

1. 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变

2. 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节

观察者模式的有点:
1. Subject和Observer之间是松耦合的,分别可以各自独立改变
2. Subject发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知
3. 遵守大部分GRASP原则和常用设计原则,高内聚低耦合




Spirng中的事件

Spring提供的事件驱动模型体系图

image

事件

具体代表者是: ApplicationEvent

  1. 继承自JDk的EventObject,JDK要求所有事件继承它,并通过source得到事件原,比如我们的AWT事件也是继承它
  2. 系统默认提供如下ApplicationEvent事件实现:

image

只有一个ApplicationContextEvent,表示ApplicationContext容器事件,且其又有如下实现:

  • ContextStartedEvent:ApplicationContext启动后触发的事件;(目前版本没有任何作用)
  • ContextStoppedEvent:ApplicationContext停止后触发的事件;(目前版本没有任何作用)
  • ContextRefreshedEvent:ApplicationContext初始化或刷新完成后触发的事件;(容器初始化完成后调用)
  • ContextClosedEvent:ApplicationContext关闭后触发的事件;(如web容器关闭时自动会触发spring容器的关闭,如果是普通java应用,需要调用ctx.registerShutdownHook();注册虚拟机关闭时的钩子才行)

注:org.springframework.context.support.AbstractApplicationContext抽象类实现了LifeCycle的start和stop回调并发布ContextStartedEvent和ContextStoppedEvent事件;但是无任何实现调用它,所以目前无任何作用。

目标(发布事件者)

具体代表者是:ApplicationEventPublisher及ApplicationEventMulticaster,系统默认提供了如下实现:

image

1 . ApplicationContext接口继承了ApplicationEventPublisher,并在AbstractApplicationContext实现了具体代码,实际执行是委托给ApplicationEventMulticaster(可以认为是多播):

public void publishEvent(ApplicationEvent event) {  
    //省略部分代码  
    }  
    getApplicationEventMulticaster().multicastEvent(event);  
    if (this.parent != null) {  
        this.parent.publishEvent(event);  
    }  
}

我们常用的ApplicationContext都继承自AbstractApplicationContext,如ClassPathXmlApplicationContext、XmlWebApplicationContext等。所以自动拥有这个功能。

  1. ApplicationContext自动到本地容器里找一个名字为”AbstractApplicationEventMulticaster”的ApplicationEventMulticaster实现,如果没有自己new一个SimpleApplicationEventMulticaster。其中SimpleApplicationEventMulticaster发布事件的代码如下:
public void multicastEvent(final ApplicationEvent event) {  
    for (final ApplicationListener listener : getApplicationListeners(event)) {  
        Executor executor = getTaskExecutor();  
        if (executor != null) {  
            executor.execute(new Runnable() {  
                public void run() {  
                    listener.onApplicationEvent(event);  
                }  
            });  
        }  
        else {  
            listener.onApplicationEvent(event);  
        }  
    }  
}


监听器

具体代表者是:ApplicationListener

1.其继承自JDK的EventLister,JDK要求所有监听器将继承它,比如我们的AWT事件体系也是继承自它;

2.ApplicationListener接口

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

其只提供了onApplicationEvent方法,我们需要在该方法实现内部判断事件类型来处理,也没有提供按顺序触发监听器的语义,所以Spring提供了另一个接口,SmartApplicationListener:


public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {  
        //如果实现支持该事件类型 那么返回true  
    boolean supportsEventType(Class<? extends ApplicationEvent> eventType);  
    
        //如果实现支持“目标”类型,那么返回true  
    boolean supportsSourceType(Class<?> sourceType);  
         
        //顺序,即监听器执行的顺序,值越小优先级越高  
        int getOrder();  
}  

该接口可方便实现去判断支持的事件类型、目标类型,及执行顺序。

Spring 事件机制的简单例子

  1. 定义事件
package com.sishuok.hello;  
import org.springframework.context.ApplicationEvent;  
public class ContentEvent extends ApplicationEvent {  
    public ContentEvent(final String content) {  
        super(content);  
    }  
} 

  1. 定义无序监听器

之所以说无序,类似于AOP机制,顺序是无法确定的.

package com.sishuok.hello;  
import org.springframework.context.ApplicationEvent;  
import org.springframework.context.ApplicationListener;  
import org.springframework.stereotype.Component;  
@Component  
public class LisiListener implements ApplicationListener<ApplicationEvent> {  
    @Override  
    public void onApplicationEvent(final ApplicationEvent event) {  
        if(event instanceof ContentEvent) {  
            System.out.println("李四收到了新的内容:" + event.getSource());  
        }  
    }  
}  


  1. 使用@Compoent注册bean即可
  2. 在具体实现中需要判断类型是ContentEvent才可以处理;

更简单的方法是通过泛型来指定类型:


package com.sishuok.hello;  
import org.springframework.context.ApplicationListener;  
import org.springframework.stereotype.Component;  
@Component  
public class ZhangsanListener implements ApplicationListener<ContentEvent> {  
    @Override  
    public void onApplicationEvent(final ContentEvent event) {  
        System.out.println("张三收到了新的内容:" + event.getSource());  
    }  
} 


  1. 定义顺序监听器

实现SmartApplication接口即可:

package com.sishuok.hello;  
import org.springframework.context.ApplicationEvent;  
import org.springframework.context.event.SmartApplicationListener;  
import org.springframework.stereotype.Component;  
  
@Component  
public class WangwuListener implements SmartApplicationListener {  
  
    @Override  
    public boolean supportsEventType(final Class<? extends ApplicationEvent> eventType) {  
        return eventType == ContentEvent.class;  
    }  
    @Override  
    public boolean supportsSourceType(final Class<?> sourceType) {  
        return sourceType == String.class;  
    }  
    @Override  
    public void onApplicationEvent(final ApplicationEvent event) {  
        System.out.println("王五在孙六之前收到新的内容:" + event.getSource());  
    }  
    @Override  
    public int getOrder() {  
        return 1;  
    }  
}  


  
@Component  
public class SunliuListener implements SmartApplicationListener {  
  
    @Override  
    public boolean supportsEventType(final Class<? extends ApplicationEvent> eventType) {  
        return eventType == ContentEvent.class;  
    }  
  
    @Override  
    public boolean supportsSourceType(final Class<?> sourceType) {  
        return sourceType == String.class;  
    }  
  
    @Override  
    public void onApplicationEvent(final ApplicationEvent event) {  
        System.out.println("孙六在王五之后收到新的内容:" + event.getSource());  
    }  
  
    @Override  
    public int getOrder() {  
        return 2;  
    }  
}  

  1. supportsEventType:用于指定支持的事件类型,只有支持的才调用onApplicationEvent;
  2. supportsSourceType:支持的目标类型,只有支持的才调用onApplicationEvent;
  3. getOrder:即顺序,越小优先级越高

转载至开涛的博客


相关文章

上一篇 spring之注解

评论