注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

北漂的小羊

Java编程,开发者,程序员,软件开发,编程,代码。新浪微博号:IT国子监

 
 
 

日志

 
 
关于我

在这里是面向程序员的高品质IT技术学习社区,是程序员学习成长的地方。让我们更好地用技术改变世界。请关注新浪微博号: IT国子监(http://weibo.com/itguozijian)

网易考拉推荐

Spring中ApplicationContext对事件处理机制的支持  

2013-01-06 14:01:24|  分类: spring |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |


Java提供了事件机制,在使用spring的时候,我们可以把普通的java事件操作定义为bean集成到bean容器中,但还有一种更方便的方式,即使用spring已集成的事件支持。 
在使用Spring的事件支持时,我们需要关注以下几个对象: 
      1. ApplicationEvent:继承自EventObject,同时是spring的application中事件的父类,需要被自定义的事件继承。 
      2. ApplicationListener:继承自EventListener,spring的application中的监听器必须实现的接口,需要被自定义的监听器实现其onApplicationEvent方法 
      3. ApplicationEventPublisherAware:在spring的context中希望能发布事件的类必须实现的接口,该接口中定义了设置ApplicationEventPublisher的方法,由ApplicationContext调用并设置。在自己实现的ApplicationEventPublisherAware子类中,需要有ApplicationEventPublisher属性的定义。 
      4. ApplicationEventPublisher:spring的事件发布者接口,定义了发布事件的接口方法publishEvent。因为ApplicationContext实现了该接口,因此spring的ApplicationContext实例具有发布事件的功能(publishEvent方法在AbstractApplicationContext中有实现)。在使用的时候,只需要把ApplicationEventPublisher的引用定义到ApplicationEventPublisherAware的实现中,spring容器会完成对ApplicationEventPublisher的注入。 

在spring的bean配置中,因为事件是由事件源发出的,不需要注册为bean由spring容器管理。所以在spring的配置中,只需配置自定义的ApplicationEventListener和publisherAware(即实现了ApplicationEventPublisherAware接口的发布类),而对于ApplicationEventPublisher的管理和注入都由容器来完成。 


Spring中事件模型的实现。 
事件类:需要继承ApplicationEvent类。
发送者:需要实现ApplicationEventPublisherAware接口。同时需要托管给容器。
接受者:需要实现ApplicationListener接口。同时需要托管给容器。


发送者调用publishEvent发送事件,接受者收到事件后进行处理

 

需要注意的是Spring3.0后:

对于接受者ApplicationListener<E extends ApplicationEvent>,多了泛型,泛型的类型决定了要关注的事件。

因为发送的事件,所有的接受者都可以收到。现在可以根据泛型进行过滤了。

如果泛型直接指定为ApplicationEvent,则接收所有事件,包括容器自身的一些事件。


ApplicationContext具有发布事件的能力。这是因为该接口继承了ApplicationEventPublisher接口。Spring中与事件有关的接口和类主要包括ApplicationEvent、ApplicationListener。
定义一个事件的类需要继承ApplicationEvent或者ApplicationContextEvent抽象类,该抽象类中只有一个构造函数,并 且带有一个Object类型的参数作为事件源,并且该事件源不能为null,因此我们需要在自己的构造函数中执行super(Object)。


Java代码 
  1. <strong>public class UserEvent extends ApplicationEvent  
  2. {  
  3.    private String eventContent;  
  4.    public String getEventContent(){  
  5.       return eventContent;  
  6.    }  
  7.    public void setEventContent(String eventContent){  
  8.       this.eventContent = eventContent;  
  9.    }  
  10.    public UserEvent(Object source,String eventContent){  
  11.       super(source);  
  12.       this.eventContent = eventContent;  
  13.    }  
  14. }</strong>  
 
针对一种事件,可能需要特定的监听器,因此,监听器需要实现ApplicationListener接口。当监听器接收到一个事件的时候,就会执行它的 onApplicationEvent()方法。由于Spring IoC中的事件模型是一种简单的、粗粒度的监听模型,当有一个事件到达时,所有的监听器都会接收到,并且作出响应,如果希望只针对某些类型进行监听,需要 在代码中进行控制。
Java代码 
  1. public class UserListener implements ApplicationListener  
  2. {  
  3.    public void onApplicationEvent(ApplicationEvent event){  
  4.       if(event instanceof UserEvent){ //只对UserEvent类型进行处理  
  5.          UserEvent ue = (UserEvent)event;  
  6.          String result = ue.getEventContent();  
  7.          System.out.println("Event Content:"+result);  
  8.       }  
  9.    }  
  10. }  
 
对于发布事件,我们可以实现ApplicationContextAware或者ApplicationEventPublisherAware接口。
Java代码  收藏代码
  1. public class UserBiz implements ApplicationContextAware  
  2. {  
  3. private ApplicationContext applicationContext;  
  4. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException  
  5. {  
  6.     this.applicationContext = applicationContext;   
  7. }  
  8. public void service(String thing)  
  9. {  
  10.     UserEvent event = new UserEvent(this,thing);  
  11.     event.setEventContent("I shoud "+thing);  
  12.     applicationContext.publishEvent(event);  
  13. }     
  14. }  
 
或者如下:
Java代码 
  1. public class UserBiz2 implements ApplicationEventPublisherAware  
  2. {  
  3.     private ApplicationEventPublisher applicationEventPublisher;  
  4.     public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)  
  5.     {  
  6.         this.applicationEventPublisher = applicationEventPublisher;  
  7.     }  
  8.     public void service(String thing)  
  9.     {  
  10.         UserEvent event = new UserEvent(this,thing);  
  11.         event.setEventContent("I shoud "+thing);  
  12.         applicationEventPublisher.publishEvent(event);  
  13.     }  
  14. }  
 
至此便完成了事件的发布,当ApplicationContext接收到事件后,事件的广播是Spring内部给我们做的,不需要了解具体的细节。其实在 Spring读取配置文件之后,利用反射,将所有实现ApplicationListener的Bean找出来,注册为容器的事件监听器。当接收到事件的 时候,Spring会逐个调用事件监听器。剩下要做的就是在配置文件中配置监听器。
<bean class="footprint.spring.ioc.event.UserListener"/>
Spring容器自身会发布一些事件,包括ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent。


以下是来自网络上的例子,大家可以看一下

 如果仅仅使用Spring的内定事件,那显然是远远不够的,幸好,Spring为我们提供了中自定义发布事件的能力。下面通过例程来展示如何发布并监听自定义的事件。

在工程中,我们定义一个Animal类,为受管Bean,它具有一个Speak方法,我们要做的就是监视该方法,当用户调用该方法时触发AnimalSpeakEvent事件。具体操作如下:

新建名字为IoC_Test3.9的java工程,添加Spring开发能力后,建立ioc.test包。新建一个事件类AnimalSpeakEvent,它继承自ApplicationEvent,重载其默认的构造方法。再添加一个String成员animalName和它的Geter方法。添加一个构造方法,此方法有两个参数,一个为source,一个为animalName。代码如下:

 1 package ioc.test;
 2 
 3 import org.springframework.context.ApplicationEvent;
 4 
 5 public class AnimalSpeakEvent extends ApplicationEvent {
 6 
 7     private static final long serialVersionUID = 1L;
 8 
 9     private String animalName;
10 
11     public AnimalSpeakEvent(Object source) {
12         super(source);
13     }
14 
15     public AnimalSpeakEvent(Object source,String animalName) {
16         super(source);
17         this.animalName = animalName;
18     }
19 
20     public String getAnimalName() {
21         return animalName;
22     }
23 
24 }
25 

创建好该事件类后,就应该把它再合适的时候发布出去。既然它时一个“动物讲话事件”,那么就应该再动物“讲话”的时候发布,如何发布呢?我们知道要发布一个事件,就必须要调用ApplicationContextpublishEvent方法。要在Animal类中获得ApplicationContext的实例,就要实现ApplicationContextAware接口,代码如下:

 

 1 package ioc.test;
 2 
 3 //import省略
 4 
 5 public class Animal implements ApplicationContextAware {
 6 
 7     private ApplicationContext ac;
 8 
 9     private String name;
10 
11     private int age;
12 
13     public String speak(){
14 
15          ac.publishEvent(new AnimalSpeakEvent(this,this.name));
16         return " 我的名字是;"+this.name+",我的年龄是:"+this.age;
17    }
18 
19 
20    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
21     this.ac = arg0;
22    }
23 
24 //Getet和Seter省略
25 
26 }
27 

到目前为之,我们已经在Animal类中把事件发布出去了,现在要监听该事件的发生了,至于监听方法,前面已经演示过,直接上代码:

 

 

 1 ackage ioc.test;
 2 
 3 import org.springframework.context.ApplicationEvent;
 4 import org.springframework.context.ApplicationListener;
 5 
 6 public class AnimalEventListener implements ApplicationListener {
 7 
 8     public void onApplicationEvent(ApplicationEvent event) {
 9         if (event instanceof AnimalSpeakEvent) {
10             AnimalSpeakEvent a = (AnimalSpeakEvent) event;
11                 System.out.println("事件监听器" + this.getClass().getSimpleName()+":有一个动物在讲话!它的名字是:"+ a.getAnimalName());
12         }
13     }
14 }
15 

配置好Bean,为AnimalBean注入值,配置文件如下:

 

 

 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans  …………>
 3 
 4     <bean id="Listener" class="ioc.test.AnimalEventListener" />
 5 
 6     <bean id="Animal" class="ioc.test.Animal">
 7       <property name="name" value="老虎" />
 8       <property name="age" value="5" />
 9     </bean>
10 
11 </beans>
12 

现在应该来测试一下了,看看我们的自定义的事件是不是会再动物“讲话”的时候发生,测试类TestMain代码如下: 

 

 

 1 package ioc.test;
 2 
 3 import org.springframework.context.support.AbstractApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 public class TestMain {
 7 
 8     public static void main(String[] args) {
 9 
10         AbstractApplicationContext ac = new ClassPathXmlApplicationContext(
11                 "applicationContext.xml");
12 
13         //从容器获取动物实例
14         Animal animal = (Animal)ac.getBean("Animal");
15 
16         //让动物讲话
17         System.out.println(animal.speak());                
18     }
19 }
20 

运行该类中的主方法,输出结果如下: 

Spring中ApplicationContext对事件处理机制的支持 - 天涯草 - 天涯草
 

可以看到,再动物“讲话“之前,我们的事件监听器监听到“动物讲话”,并输出了讲话动物的名字。

 

  评论这张
 
阅读(696)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016