详解Spring事件驱动模型

时间:2021-03-12 09:26:43

转载自:http://jinnianshilongnian.iteye.com/blog/1902886#comments

事件驱动模型简介

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

  1. 首先是一种对象间的一对多的关系;最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方);
  2. 当目标发送改变(发布),观察者(订阅者)就可以接收到改变;
  3. 观察者如何处理(如行人如何走,是快走/慢走/不走,目标不会管的),目标无需干涉;所以就松散耦合了它们之间的关系。

接下来先看一个用户注册的例子:

详解Spring事件驱动模型

用户注册成功后,需要做这么多事:

1、加积分

2、发确认邮件

3、如果是游戏帐户,可能赠送游戏大礼包

4、索引用户数据

…………

问题:

  1. UserService和其他Service耦合严重,增删功能比较麻烦;
  2. 有些功能可能需要调用第三方系统,如增加积分/索引用户,速度可能比较慢,此时需要异步支持;这个如果使用Spring,可以轻松解决,后边再介绍;

从如上例子可以看出,应该使用一个观察者来解耦这些Service之间的依赖关系,如图:

详解Spring事件驱动模型

增加了一个Listener来解耦UserService和其他服务,即注册成功后,只需要通知相关的监听器,不需要关系它们如何处理。增删功能非常容易。

这就是一个典型的事件处理模型/观察者,解耦目标对象和它的依赖对象,目标只需要通知它的依赖对象,具体怎么处理,依赖对象自己决定。比如是异步还是同步,延迟还是非延迟等。

上边其实也使用了DIP(依赖倒置原则),依赖于抽象,而不是具体。

还是就是使用了IoC思想,即以前主动去创建它依赖的Service,现在只是被动等待别人注册进来。

其他的例子还有如GUI中的按钮和动作的关系,按钮和动作本身都是一种抽象,每个不同的按钮的动作可能不一样;如“文件-->新建”打开新建窗口;点击“关闭”按钮关闭窗口等等。

主要目的是:松散耦合对象间的一对多的依赖关系,如按钮和动作的关系;

如何实现呢?面向接口编程(即面向抽象编程),而非面向实现。即按钮和动作可以定义为接口,这样它俩的依赖是最小的(如在Java中,没有比接口更抽象的了)。

有朋友会问,我刚开始学的时候也是这样:抽象类不也行吗?记住一个原则:接口目的是抽象,抽象类目的是复用;所以如果接触过servlet/struts2/spring等框架,大家都应该知道:

  • Servlet<-----GenericServlet<-----HttpServlet<------我们自己的
  • Action<------ActionSupport<------我们自己的
  • DaoInterface<------××DaoSupport<-----我们自己的

从上边大家应该能体会出接口、抽象类的主要目的了。现在想想其实很简单。

在Java中接口还一个非常重要的好处:接口是可以多实现的,类/抽象类只能单继承,所以使用接口可以非常容易扩展新功能(还可以实现所谓的mixin),类/抽象类办不到。

Java GUI事件驱动模型/观察者

扯远了,再来看看Java GUI世界里的事件驱动模型吧

如果写过AWT/Swing程序,应该知道其所有组件都继承自java.awt.Component抽象类,其内部提供了addXXXListener(XXXListener l) 注册监听器的方法,即Component与实际动作之间依赖于XXXListener抽象。

比如获取焦点事件,很多组件都可以有这个事件,是我们知道组件获取到焦点后需要一个处理,虽然每个组件如何处理是特定的(具体的),但我们可以抽象一个FocusListener,让所有具体实现它然后提供具体动作,这样组件只需依赖于FocusListener抽象,而不是具体。

还有如java.awt.Button,提供了一个addActionListener(ActionListener l),用于注册点击后触发的ActionListener实现。

组件是一个抽象类,其好处主要是复用,比如复用这些监听器的触发及管理等。

Java提供的事件驱动模型/观察者抽象

JDK内部直接提供了观察者模式的抽象:

目标:java.util.Observable,提供了目标需要的关键抽象:addObserver/deleteObserver/notifyObservers()等,具体请参考javadoc。

观察者:java.util.Observer,提供了观察者需要的主要抽象:update(Observable o, Object arg),此处还提供了一种推模型(目标主动把数据通过arg推到观察者)/拉模型(目标需要根据o自己去拉数据,arg为null)。

因为网上介绍的非常多了,请google搜索了解如何使用这个抽象及推/拉模型的优缺点。

接下来是我们的重点:spring提供的事件驱动模型。

Spring提供的事件驱动模型/观察者抽象

首先看一下Spring提供的事件驱动模型体系图:

详解Spring事件驱动模型

事件

具体代表者是:ApplicationEvent:

1、其继承自JDK的EventObject,JDK要求所有事件将继承它,并通过source得到事件源,比如我们的AWT事件体系也是继承自它;

2、系统默认提供了如下ApplicationEvent事件实现:

详解Spring事件驱动模型

只有一个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,系统默认提供了如下实现:

详解Spring事件驱动模型

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

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);
}
}

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

2、ApplicationContext自动到本地容器里找一个名字为”“的ApplicationEventMulticaster实现,如果没有自己new一个SimpleApplicationEventMulticaster。其中SimpleApplicationEventMulticaster发布事件的代码如下:

@SuppressWarnings("unchecked")
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);
}
}
}

大家可以看到如果给它一个executor(java.util.concurrent.Executor),它就可以异步支持发布事件了。佛则就是通过发送。

所以我们发送事件只需要通过ApplicationContext.publishEvent即可,没必要再创建自己的实现了。除非有必要。

监听器

具体代表者是:ApplicationListener

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

2、ApplicationListener接口:

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

    /**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event); }

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

public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {

    /**
* Determine whether this listener actually supports the given event type.
*/
boolean supportsEventType(Class<? extends ApplicationEvent> eventType); /**
* Determine whether this listener actually supports the given source type.
*/
boolean supportsSourceType(Class<?> sourceType); }

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

Spring事件机制的简单例子

本例子模拟一个给多个人发送内容(类似于报纸新闻)的例子。

1、定义事件

import org.springframework.context.ApplicationEvent;

public class ContentEvent extends ApplicationEvent {
public ContentEvent(final String content) {
super(content);
}
}

非常简单,如果用户发送内容,只需要通过构造器传入内容,然后通过getSource即可获取。

2、定义无序监听器

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

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("当前线程" + Thread.currentThread().getName());
System.out.println("李四收到了新的内容:" + event.getSource());
}
}
}

1、使用@Compoent注册Bean即可;

2、在实现中需要判断event类型是ContentEvent才可以处理;

更简单的办法是通过泛型指定类型,如下所示

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("当前线程" + Thread.currentThread().getName());
System.out.println("张三收到了新的内容:" + event.getSource());
}
}

3、定义有序监听器

实现SmartApplicationListener接口即可。

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("当前线程" + Thread.currentThread().getName());
System.out.println("王五在孙六之前收到新的内容:" + event.getSource());
}
@Override
public int getOrder() {
return 1;
}
}
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component; @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("当前线程" + Thread.currentThread().getName());
System.out.println("孙六在王五之后收到新的内容:" + event.getSource());
} @Override
public int getOrder() {
return 2;
}
}
  1. supportsEventType:用于指定支持的事件类型,只有支持的才调用onApplicationEvent;
  2. supportsSourceType:支持的目标类型,只有支持的才调用onApplicationEvent;
  3. getOrder:即顺序,越小优先级越高

4、测试

4.1、配置文件

<context:component-scan base-package="com.winner"/>

就一句话,自动扫描注解Bean。

4.2、测试类

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring-config-hello.xml"})
public class HelloIT { @Autowired
private ApplicationContext applicationContext;
@Test
public void testPublishEvent() {
applicationContext.publishEvent(new ContentEvent("今年是龙年的博客更新了"));
}
}

接着会输出:

当前线程main
王五在孙六之前收到新的内容:今年是龙年的博客更新了
当前线程main
孙六在王五之后收到新的内容:今年是龙年的博客更新了
当前线程main
李四收到了新的内容:今年是龙年的博客更新了
当前线程main
张三收到了新的内容:今年是龙年的博客更新了

他们是在同一个线程中执行的!

一个简单的测试例子就演示完毕,而且我们使用spring的事件机制去写相关代码会非常简单。

Spring事件机制实现之前提到的注册流程

这里讲解一下Spring对异步事件机制的支持,实现方式有两种:

1、全局异步

即只要是触发事件都是以异步执行,具体配置(spring-config-register.xml)如下:

<task:executor id="executor" pool-size="10" />
<!-- 名字必须是applicationEventMulticaster和messageSource是一样的,默认找这个名字的对象 -->
<!-- 名字必须是applicationEventMulticaster,因为AbstractApplicationContext默认找个 -->
<!-- 如果找不到就new一个,但不是异步调用而是同步调用 -->
<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
<!-- 注入任务执行器 这样就实现了异步调用(缺点是全局的,要么全部异步,要么全部同步(删除这个属性即是同步)) -->
<property name="taskExecutor" ref="executor"/>
</bean>

通过注入taskExecutor来完成异步调用。具体实现可参考之前的代码介绍。这种方式的缺点很明显:要么大家都是异步,要么大家都不是。所以不推荐使用这种方式。

2、更灵活的异步支持

spring3提供了@Aync注解来完成异步调用。此时我们可以使用这个新特性来完成异步调用。不仅支持异步调用,还支持简单的任务调度,比如我的项目就去掉Quartz依赖,直接使用spring3这个新特性,具体可参考spring-config.xml

2.1、开启异步调用支持

<!-- 开启@AspectJ AOP代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/> <!-- 任务调度器 -->
<task:scheduler id="scheduler" pool-size="10"/> <!-- 任务执行器 -->
<task:executor id="executor" pool-size="10"/> <!--开启注解调度支持 @Async @Scheduled-->
<task:annotation-driven executor="executor" scheduler="scheduler" proxy-target-class="true"/>

2.2、配置监听器让其支持异步调用

@Component
public class EmailRegisterListener implements ApplicationListener<RegisterEvent> {
@Async
@Override
public void onApplicationEvent(final RegisterEvent event) {
System.out.println("注册成功,发送确认邮件给:" + ((User)event.getSource()).getUsername());
}
}

使用@Async注解即可,非常简单。

这样不仅可以支持通过调用,也支持异步调用,非常的灵活,实际应用推荐大家使用这种方式。

通过如上,大体了解了Spring的事件机制,可以使用该机制非常简单的完成如注册流程,而且对于比较耗时的调用,可以直接使用Spring自身的异步支持来优化。

aaarticlea/png;base64,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" alt="" />