我是
靠谱客的博主
热情手链,最近开发中收集的这篇文章主要介绍
Spring基于事件驱动模型的订阅发布模式代码实例详解,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
转载地址:http://blog.csdn.net/yaerfeng/article/details/27683813
Spring提供的事件驱动模型/观察者抽象
首先看一下Spring提供的事件驱动模型体系图:
事件
具体代表者是:ApplicationEvent:
1、其继承自JDK的EventObject,JDK要求所有事件将继承它,并通过source得到事件源,比如我们的AWT事件体系也是继承自它;
2、系统默认提供了如下ApplicationEvent事件实现:
只有一个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,系统默认提供了如下实现:
1、ApplicationContext接口继承了ApplicationEventPublisher,并在AbstractApplicationContext实现了具体代码,实际执行是委托给ApplicationEventMulticaster(可以认为是多播):
Java代码
- public void publishEvent(ApplicationEvent event) {
-
- }
- getApplicationEventMulticaster().multicastEvent(event);
- if (this.parent != null) {
- this.parent.publishEvent(event);
- }
- }
我们常用的ApplicationContext都继承自AbstractApplicationContext,如ClassPathXmlApplicationContext、XmlWebApplicationContext等。所以自动拥有这个功能。
2、ApplicationContext自动到本地容器里找一个名字为”“的ApplicationEventMulticaster实现,如果没有自己new一个SimpleApplicationEventMulticaster。其中SimpleApplicationEventMulticaster发布事件的代码如下:
Java代码
- 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接口:
Java代码
- public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
- void onApplicationEvent(E event);
- }
其只提供了onApplicationEvent方法,我们需要在该方法实现内部判断事件类型来处理,也没有提供按顺序触发监听器的语义,所以Spring提供了另一个接口,SmartApplicationListener:
Java代码
- public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
-
- boolean supportsEventType(Class<? extends ApplicationEvent> eventType);
-
-
- boolean supportsSourceType(Class<?> sourceType);
-
-
- int getOrder();
- }
该接口可方便实现去判断支持的事件类型、目标类型,及执行顺序。
Spring事件机制的简单例子
本例子模拟一个给多个人发送内容(类似于报纸新闻)的例子。
1、定义事件
Java代码
- package com.zuidaima.hello;
- import org.springframework.context.ApplicationEvent;
- public class ContentEvent extends ApplicationEvent {
- public ContentEvent(final String content) {
- super(content);
- }
- }
非常简单,如果用户发送内容,只需要通过构造器传入内容,然后通过getSource即可获取。
2、定义无序监听器
之所以说无序,类似于AOP机制,顺序是无法确定的。
Java代码
- package com.zuidaima.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、在实现中需要判断event类型是ContentEvent才可以处理;
更简单的办法是通过泛型指定类型,如下所示
Java代码
- package com.zuidaima.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());
- }
- }
3、定义有序监听器
实现SmartApplicationListener接口即可。
Java代码
- package com.zuidaima.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;
- }
- }
Java代码
- package com.zuidaima.hello;
- 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("孙六在王五之后收到新的内容:" + event.getSource());
- }
-
- @Override
- public int getOrder() {
- return 2;
- }
- }
- supportsEventType:用于指定支持的事件类型,只有支持的才调用onApplicationEvent;
- supportsSourceType:支持的目标类型,只有支持的才调用onApplicationEvent;
- getOrder:即顺序,越小优先级越高
4、测试
4.1、配置文件
Java代码
- <context:component-scan base-package="com.zuidaima"/>
就一句话,自动扫描注解Bean。
4.2、测试类
Java代码
- package com.zuidaima;
- import com.zuidaima.hello.ContentEvent;
- 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("今年是龙年的博客更新了"));
- }
-
- }
接着会输出:
Java代码
- 王五在孙六之前收到新的内容:今年是龙年的博客更新了
- 孙六在王五之后收到新的内容:今年是龙年的博客更新了
- 李四收到了新的内容:今年是龙年的博客更新了
- 张三收到了新的内容:今年是龙年的博客更新了
一个简单的测试例子就演示完毕,而且我们使用spring的事件机制去写相关代码会非常简单。
最后
以上就是热情手链为你收集整理的Spring基于事件驱动模型的订阅发布模式代码实例详解的全部内容,希望文章能够帮你解决Spring基于事件驱动模型的订阅发布模式代码实例详解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复