7.4.4 ApplicationContext的事件机制

7.4.4 ApplicationContext的事件机制

ApplicationContext的事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext的事件处理。如果容器中有一个ApplicationListener Bean每当ApplicationContext发布ApplicationEvent时, ApplicationListener Bean将自动被触发。
Spring的事件框架有如下两个重要成员。

  • ApplicationEvent:容器事件,必须由ApplicationContext发布。
  • ApplicationListener:监听器,可由容器中的任何监听器Bean担任。

实际上, Spring的事件机制与所有的事件机制都基本相似,它们都需要由事件源事件事件监听器组成。只是此处的事件源是ApplicationContext,且事件必须由Java程序显式触发。

程序示例

项目结构

1
2
3
4
5
6
7
8
9
10
11
12
E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\EventHandler
└─src\
├─beans.xml
├─lee\
│ └─SpringTest.java
└─org\
└─crazyit\
└─app\
├─event\
│ └─EmailEvent.java
└─listener\
└─EmailNotifier.java

下面的程序将示范Spring容器的事件机制。程序先定义了一个ApplicationEvent类,其对象就是个Spring容器事件。 ApplicationEvent类的代码如下。

beans.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.crazyit.app.event;
import org.springframework.context.ApplicationEvent;
public class EmailEvent extends ApplicationEvent
{
private static final long serialVersionUID = 1L;
private String address;
private String text;
public EmailEvent(Object source)
{
super(source);
}
// 初始化全部成员变量的构造器
public EmailEvent(Object source, String address, String text)
{
super(source);
this.address = address;
this.text = text;
}
// 此处省略getter和setter方法,请自己补上
}

上面的EmailEvent类继承了ApplicationEvent类,除此之外,它就是一个普通的Java类。

如何创建Spring容器的容器事件

只要个Java类继承了ApplicationEvent基类,那该对象就可作为Spring容器的容器事件。

容器事件的监听器

容器事件的监听器类必须实现ApplicationListener接口,实现该接口必须实现如下方法。
onApplicationEvent(ApplicationEvent event):每当容器内发生任何事件时,此方法都被触发

EmailNotifier.java

本示例所用的容器监听器类的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.crazyit.app.listener;

import org.crazyit.app.event.EmailEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class EmailNotifier implements ApplicationListener
{
// 该方法会在容器发生事件时自动触发
public void onApplicationEvent(ApplicationEvent evt)
{
// 只处理EmailEvent,模拟发送email通知...
if (evt instanceof EmailEvent)
{
EmailEvent emailEvent = (EmailEvent) evt;
System.out.println("需要发送邮件的接收地址 " + emailEvent.getAddress());
System.out.println("需要发送邮件的邮件正文 " + emailEvent.getText());
} else
{
// 其他事件不作任何处理
System.out.println("其他事件:" + evt);
}
}
}

将监听器配置在容器中,配置文件如下。

beans.xml

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置监听器 -->
<bean class="org.crazyit.app.listener.EmailNotifier" />
</beans>

从上面的粗体字代码可以看出,为Spring容器注册事件监听器,不需要像AWT编程那样采用代码进行编程,只要进行简单配置即可。只要在Spring中配置一个实现了ApplicationListener接口的Bean,Spring容器就会把这个Bean当成容器事件的事件监听器
当系统创建Spring容器加载Spring容器时会自动触发容器事件,容器事件监听器可以监听到这些事件。除此之外,程序也可调用ApplicationContextpulishEvent()方法来主动触发容器事件。如下主程序使用ApplicationContextpublishEvent()来触发事件。

SpringTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package lee;

import org.crazyit.app.event.EmailEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest
{
public static void main(String[] args)
{
@SuppressWarnings("resource")
ApplicationContext ctx = new
ClassPathXmlApplicationContext("beans.xml");
// 创建一个ApplicationEvent对象
EmailEvent ele = new EmailEvent("test" ,
"spring_test@163.com" , "this is a test");
// 发布容器事件
ctx.publishEvent(ele);
}
}

上面程序中的两行粗体字代码创建了ApplicationEvent对象,并通过ApplictionContex主动触发了该事件。运行上面的程序,将看到如下执行结果:

1
2
3
其他事件:org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.support.ClassPathXmlApplicationContext@439f5b3d, started on Sun Aug 25 23:06:44 CST 2019]
需要发送邮件的接收地址 spring_test@163.com
需要发送邮件的邮件正文 this is a test

从上面的执行结果可以看出,监听器不仅监听到程序所触发的事件,也监听到容器内置的事件。实际上,如果开发者需要在Spring容器初始化、销毁时回调自定义方法,就可以通过上面的事件监听器来实现
提示:一如果Bean希望发布容器事件,则该Bean必须先获得对Spring容器的引用。为了让Bean获得对Spring容器的引用,可让Bean类实现ApplicationContextAwareBeanFactoryAware接口。

Spring内置事件

Spring提供如下几个内置事件:
这里先省略,后续用到再更新…