有事件,即有事件监听器. 有人问你spring监听器有哪些你看了下文即也知道了。
 
事件传播
ApplicationContext基于Observer模式(java.util包中有对应实现),提供了针对Bean的事件传
播功能。通过Application. publishEvent方法,我们可以将事件通知系统内所有的
ApplicationListener。
 
事件传播的一个典型应用是,当Bean中的操作发生异常(如数据库连接失败),则通过事件传播
机制通知异常监听器进行处理。在笔者的一个项目中,就曾经借助事件机制,较好的实现了当系统
异常时在监视终端上报警,同时发送报警SMS至管理员手机的功能。
 

ApplicationContext容器提供了容器内部事件发布功能,是继承自JavaSE标准自定义事件类而实现的。

JavaSE标准自定义事件结构不在此详细描述,一张图很直观的描述清楚:

EventObject,为JavaSE提供的事件类型基类,任何自定义的事件都继承自该类,例如上图中右侧灰色的各个事件。Spring中提供了该接口的子类ApplicationEvent。

EventListener为JavaSE提供的事件监听者接口,任何自定义的事件监听者都实现了该接口,如上图左侧的各个事件监听者。Spring中提供了该接口的子类ApplicationListener接口。

JavaSE中未提供事件发布者这一角色类,由各个应用程序自行实现事件发布者这一角色。Spring中提供了ApplicationEventPublisher接口作为事件发布者,并且ApplicationContext实现了这个接口,担当起了事件发布者这一角色。但ApplicationContext在具体实现上有所差异,Spring提供了ApplicationEventMulticaster接口,负责管理ApplicationListener和发布ApplicationEvent。ApplicationContext会把相应的事件相关工作委派给ApplicationEventMulticaster接口实现类来做。类图如下所示:

事件发布时序图如下:

 
-------------------------------------------------------------------------------------------------

Spring中提供一些Aware相关的接口,BeanFactoryAware、 ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等,其中最常用到的是ApplicationContextAware。实现ApplicationContextAware的Bean,在Bean被初始后,将会被注入ApplicationContext的实例。ApplicationContextAware提供了publishEvent()方法,实现Observer(观察者)设计模式的事件传播机,提供了针对Bean的事件传播功能。通过Application.publishEvent方法,我们可以将事件通知系统内所有的ApplicationListener。

Spring事件处理一般过程:

◆定义Event类,继承org.springframework.context.ApplicationEvent。
◆编写发布事件类Publisher,实现org.springframework.context.ApplicationContextAware接口。
◆覆盖方法setApplicationContext(ApplicationContext applicationContext)和发布方法publish(Object obj)。
◆定义时间监听类EventListener,实现ApplicationListener接口,实现方法onApplicationEvent(ApplicationEvent event)。

1.发布

    1.1事件的发布者需要实现的接口
        org.springframework.context.ApplicationEventPublisherAware
    1.2 代码示例  

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;

/**
*
* @author zq
*
*/
public class HelloWorld implements ApplicationEventPublisherAware{
private String word;
private ApplicationEventPublisher tradeEventPublisher;

public void setWord(String w){
this.word = w;
}

public void say(){
System.out.println("say : "+ this.word);
//construct a TradeEvent instance and publish it
TradeEvent tradeEvent = new TradeEvent(new String("tradeEvent"));
this.tradeEventPublisher.publishEvent(tradeEvent);
}

@Override
public void setApplicationEventPublisher(
ApplicationEventPublisher applicationEventPublisher) {
// TODO Auto-generated method stub
this.tradeEventPublisher = applicationEventPublisher;
}
}

2.接受事件

  2.1需要实现的接口org.springframework.context.ApplicationListener
  2.2代码示例

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;

public class TradeContextListener implements ApplicationListener{

@Override
public void onApplicationEvent(ApplicationEvent e) {

System.out.println(e.getClass().toString());
// TODO Auto-generated method stub
if (e instanceof ContextStartedEvent){
System.out.println("it was contextStartedEvent");
}

if (e instanceof TradeEvent){
System.out.println(e.getSource());
}

}

}

3配置文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="helloWorld" class="study.HelloWorld">
<property name="word" value="hello world"/>
</bean>

<bean id="tradeContextListener" class="study.TradeContextListener"/>
</beans>

4.测试代码

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import study.HelloWorld;
public class TestHelloWorld {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("study-context.xml");
HelloWorld bean = (HelloWorld)applicationContext.getBean("helloWorld");
bean.say();
}

}

 
Spring中ApplicationContext的事件机制--- 内定事件)
在Spring中已经定义了五个标准事件,分别介绍如下:

1)      ContextRefreshedEvent:当ApplicationContext初始化或者刷新时触发该事件。

2)      ContextClosedEvent:当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。

3)      RequestHandleEvent:在Web应用中,当一个http请求(request)结束触发该事件。

ContestStartedEvent:Spring2.5新增的事件,当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。

5) ContestStopedEvent:Spring2.5新增的事件,当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。

下面通过一个例子展示如何处理Spring内定的事件(例程3.8)。创建一个Java工程,添加Spring开发能力后,新建ioc.test包。在包中新建ApplicationEventListener类,实现ApplicationListener接口,在onApplicationEvent()方法中添加事件处理代码,如下:

1 package ioc.test;

3 //Import省略
4 publicclass ApplicationEventListenerimplements ApplicationListener {

6 publicvoid onApplicationEvent(ApplicationEvent event) {

8 //如果是容器刷新事件
9 if(eventinstanceof ContextClosedEvent ){
10             System.out.println(event.getClass().getSimpleName()+" 事件已发生!");   
11         }elseif(eventinstanceof ContextRefreshedEvent ){//如果是容器关闭事件
12             System.out.println(event.getClass().getSimpleName()+" 事件已发生!");   
13         }elseif(eventinstanceof ContextStartedEvent ){
14             System.out.println(event.getClass().getSimpleName()+" 事件已发生!");
15         }elseif(eventinstanceof ContextStoppedEvent){
16             System.out.println(event.getClass().getSimpleName()+" 事件已发生!");
17         }else{
18             System.out.println("有其它事件发生:"+event.getClass().getName());
19         }
20                    
21     }
22 
23 }
24 

在Spring配置文件中定义一个Bean,类为ApplicationEventListener,代码如下:

1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans…………   

4    <bean id="ApplicationEventListener" class="ioc.test.ApplicationEventListener"/>

6 </beans>
7

添加含有主方法的TesMain类,在主方法中,调用容器的相应方法,触发Spring内定事件,代码如下:

1 package ioc.test;

3 //import省略
4 publicclass TesMain {

6 publicstaticvoid main(String[] args) {
7         AbstractApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
8         

10 //    ac.refresh();//触发ContextRefreshedEvent事件           
11         ac.start();//触发ContextStartedEvent事件
12         ac.stop(); //触发ContextStoppedEvent事件       
13         ac.close();//关闭容器,触发ContextClosedEvent事件
14 
15     }
16 }
17

运行主类,控制台输出如下:

从例子中可以知道,要注册事件监听器,我们只需要把它配置成一个Bean即可,ApplicationContext容器会自动将其注册

spring发布和接收定制的事件(spring事件传播)[转]的更多相关文章

  1. spring发布和接收定制的事件(spring事件传播)

    spring发布和接收定制的事件(spring事件传播) 2012-12-26 20:05 22111人阅读 评论(2) 收藏 举报  分类: 开源技术(如Struts/spring/Hibernat ...

  2. 从spring源码汲取营养:模仿spring事件发布机制,解耦业务代码

    前言 最近在项目中做了一项优化,对业务代码进行解耦.我们部门做的是警用系统,通俗的说,可理解为110报警.一条警情,会先后经过接警员.处警调度员.一线警员,警情是需要记录每一步的日志,是要可追溯的,比 ...

  3. Spring Boot实战之定制自己的starter

    本文首发于个人网站,原文地址:http://www.javaadu.online/?p=535,如需转载,请注明出处 在学习Spring Boot的过程中,接触最多的就是starter.可以认为sta ...

  4. Spring boot实现监听Redis key失效事件实现和其它方式

    需求: 处理订单过期自动取消,比如下单30分钟未支付自动更改订单状态 用户绑定隐私号码当订单结束取消绑定等 解决方案1: 可以利用redis自带的key自动过期机制,下单时将订单id写入redis,过 ...

  5. Spring 4.2框架中注释驱动的事件监听器详解

    事件交互已经成为很多应用程序不可或缺的一部分,spring框架提供了一个完整的基础设施来处理瞬时事件.下面我们来看看Spring 4.2框架中基于注释驱动的事件监听器. 1.早期的方式 在早期,组件要 ...

  6. Spring Boot实战之定制URL匹配规则

    本文首发于个人网站:Spring Boot实战之定制URL匹配规则 构建web应用程序时,并不是所有的URL请求都遵循默认的规则.有时,我们希望RESTful URL匹配的时候包含定界符". ...

  7. Spring Boot实战之定制type Formatters

    本文首发于个人网站:Spring Boot实战之定制type Formatters 前面我们有篇文章介绍了PropertyEditors,是用来将文本类型转换成指定的Java类型,不过,考虑到Prop ...

  8. 解决cxf+spring发布的webservice,types,portType和message以import方式导入

    用cxf+spring发布了webservice,发现生成的wsdl的types,message和portType都以import的方式导入的.. 原因:命名空间问题 我想要生成的wsdl在同个文件中 ...

  9. Spring MVC在接收复杂集合参数

    Spring MVC在接收集合请求参数时,需要在Controller方法的集合参数里前添加@RequestBody,而@RequestBody默认接收的enctype (MIME编码)是applica ...

随机推荐

  1. svn 出现冲突时可以使用 meld . 命令合并。 而git的冲突合并详见内容

    1.可以在任意目录使用 git mergetool --tool-help    查看 git 所支持的merge tools. 2.可以使用如下配置去设置merge tool 和 diff tool ...

  2. python之virtualenv 与 virtualenvwrapper 详解

    在使用 Python 开发的过程中,工程一多,难免会碰到不同的工程依赖不同版本的库的问题: 亦或者是在开发过程中不想让物理环境里充斥各种各样的库,引发未来的依赖灾难. 此时,我们需要对于不同的工程使用 ...

  3. 原生Base64编码/解码(OC与Swift)

    Objective-C NSString *plainString = @"foo"; Encoding NSData *plainData = [plainString data ...

  4. [UVA 12633] Super Rooks on Chessboard FFT+计数

    如果只有行和列的覆盖,那么可以直接做,但现在有左上到右下的覆盖. 考虑对行和列的覆盖情况做一个卷积,然后就有了x+y的非覆盖格子数. 然后用骑士的左上到右下的覆盖特判掉那些x+y的格子就可以了. 注意 ...

  5. Python成长之路第一篇(2)__初识列表和元组

    可以将列表和元组当成普通的“数组”,他能保存任意数量任意类型的Python对象,和数组一样都是通过数字0索引访问元素,列表和元组可以存储不同类型的对象,列表和元组有几处重要区别.列表元素用([])包括 ...

  6. L84

    Hospital Noise May Disrupt Patient Improvement Many who need restorative rest the most might not be ...

  7. Visual Studio 2012简体中文专业版密钥(激活码)

    VS2012 正式版在Beta版的基础上进行了很多改进,尤其是加入了全新的用户界面. VS2012 的硬件需求与VS2010相同,不过由于 Visual Studio 2012 利用了新版 Windo ...

  8. BZOJ_3159_决战

    题目链接 分析: 我使用树剖+splay维护这个东西. 对每条重链维护一棵splay,链加和查询正常做,剩下的链反转如下. 由于一定是深度递增的一条链,我们树剖将它分成从左到右log个区间,提取出对应 ...

  9. 四维偏序 CDQ套CDQ

    对CDQ深一步的理解 昨天做了一道CDQ,看了一堆CDQ可做的题,今天又做了一道四维偏序 感觉对CDQ的理解又深了一点,故来写一写现在自己对于CDQ的理解 CDQ其实就是实现了这样的一个问题的转化: ...

  10. bzoj4555: 求和sum 快速傅立叶变换

    题目大意 给定\(S(n,m)\)表示第二类斯特林数,定义函数\(f(n)\) \[f(n) = \sum_{i=0}^n\sum_{j=0}^iS(i,j)*2^j*(j!)\] 给定正整数\(n, ...