什么是ApplicationContext?
它是spring的核心,Context我们通常解释为上下文环境,但是理解成容器会更好些。
ApplicationContext则是应用的容器。
Spring把Bean(object)放在容器中,需要用就通过get方法取出来。
ApplicationEvent
是个抽象类,里面只有一个构造函数和一个长整型的timestamp。
ApplicationListener
是一个接口,里面只有一个onApplicationEvent方法。
所以自己的类在实现该接口的时候,要实装该方法。
如果在上下文中部署一个实现了ApplicationListener接口的bean,
那么每当在一个ApplicationEvent发布到 ApplicationContext时,
这个bean得到通知。其实这就是标准的Oberver设计模式。
下面给出例子:
首先创建一个ApplicationEvent实现类:
1 package com.spring.event; 2 3 import org.springframework.context.ApplicationEvent; 4 5 public class EmailEvent extends ApplicationEvent { 6 /** 7 * <p>Description:</p> 8 */ 9 private static final long serialVersionUID = 1L; 10 public String address; 11 public String text; 12 13 public EmailEvent(Object source) { 14 super(source); 15 } 16 17 public EmailEvent(Object source, String address, String text) { 18 super(source); 19 this.address = address; 20 this.text = text; 21 } 22 23 public void print(){ 24 System.out.println("hello spring event!"); 25 } 26 27 }
给出监听器:
1 package com.spring.event; 2 3 import org.springframework.context.ApplicationEvent; 4 import org.springframework.context.ApplicationListener; 5 public class EmailListener implements ApplicationListener { 6 7 public void onApplicationEvent(ApplicationEvent event) { 8 if(event instanceof EmailEvent){ 9 EmailEvent emailEvent = (EmailEvent)event; 10 emailEvent.print(); 11 System.out.println("the source is:"+emailEvent.getSource()); 12 System.out.println("the address is:"+emailEvent.address); 13 System.out.println("the email's context is:"+emailEvent.text); 14 } 15 16 } 17 18 }
applicationContext.xml文件配置:
<bean id="emailListener" class="com.spring.event.EmailListener"></bean>
测试类:
1 package com.spring.event; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 public class Test { 7 public static void main(String[] args) { 8 ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); 9 10 //HelloBean hello = (HelloBean) context.getBean("helloBean"); 11 //hello.setApplicationContext(context); 12 EmailEvent event = new EmailEvent("hello","boylmx@163.com","this is a email text!"); 13 context.publishEvent(event); 14 //System.out.println(); 15 } 16 }
测试结果
hello spring event! the source is:hello the address is:boylmx@163.com the email's context is:this is a email text!
Spring 4.2框架中注释驱动的事件监听器详解
作者:chszs,版权所有,未经同意,不得转载。博主主页:http://blog.csdn.net/chszs
事件交互已经成为很多应用程序不可或缺的一部分,Spring框架提供了一个完整的基础设施来处理瞬时事件。下面我们来看看Spring 4.2框架中基于注释驱动的事件监听器。
1、早期的方式
在早期,组件要从Spring事件获知自定义域事件中获取通知,那么组件必须实现ApplicationListener接口并覆写onApplicationEvent方法。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
上面的代码工作正常,但是它会针对每一个事件都创建一个新类,从而造成代码瓶颈。
另外,我们的事件类继承了ApplicationEvent类——Spring应用中的事件基类。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
请注意,在事件中使用Domain域对象有明显的缺点,在一些场景下不可用。这里只是做代码示例。
顺便说一句,ExternalNotificationSender对象负责发送外部通知给已注册的用户(例如通过电子邮件、短信等方式)。
2、注释驱动的事件监听器
Spring 4.2框架值得注意的一点,用注释@EventListener注解任意的Spring组件。
- 1
- 2
- 3
- 4
- 5
Spring会为事件创建一个ApplicationListener实例,并从方法参数中获取事件的类型。一个类中被事件注释的方法数量没有限制,所有相关的事件句柄都会分组到一个类中。
3、有条件的事件处理
为了使注释@EventListener的功能更强大,Spring 4.2支持用SpEL表达式表达事件类型的方式。假设以下是事件类:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
要注意,在实际应用中可能不会有本文这样的层次结构的事件。
还要注意,用Groovy编写会更加简单。
使用条件参数来阐述事件,重要的变化是:
- 1
- 2
- 3
- 4
- 5
4、宽松事件类型的层次结构
Spring 4.2之前的版本,ApplicationEventPublisher只有在ApplicationEvent事件后发布其继承对象的能力。而在Spring 4.2版开始,此接口已经扩展到支持任意对象类型。在这种情况下,对象被封装到PayloadApplicationEvent和通过发送。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
这一变化使得发布事件更容易。然而另一方面它可以导致事件跟踪变得更加困难,特别是在大型应用程序中。
5、响应发布事件
注释@EventListener还有一点需注意,在非空返回类型时,Spring会自动发布返回的事件。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
6、异步事件处理
注释@EventListener还可以与注释@Async进行组合使用,以提供异步事件处理的机制。下面的代码中,指定的事件监听器既不会阻塞主要的代码执行,又不会被其它的监听器处理。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
为了使工作能够得到异步执行,通常还需在Spring项目的上下文中使用注释@EnableAsync。
7、总结
注释驱动的事件监听器是Spring框架4.2版中引入的新特性,它减少了Spring项目的样板代码,使得代码更加灵活,尤其是在小数量事件的需求时体现更为明显。