事件传播
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。
项目实例
进行发布
@Autowired private ApplicationContext context;
PublishHomeworkEvent event = new PublishHomeworkEvent(this,homeworkId,paperId,creatorId,creatorName,title,userVo);
context.publishEvent(event);
自定义发布事件
@Data
public class PublishHomeworkEvent extends ApplicationEvent {
//作业id
private String homeworkId;
//作业对应的paperId
private String paperId;
//用户id
private String creatorId;
//用户名
private String creatorName;
//标题
private String title;
//用户对象(此参数中必要参数为机构code,apiKey,第三方用户id,教研云用户id)
private UserVo userVo;
public PublishHomeworkEvent(Object source) {
super(source);
}
public PublishHomeworkEvent(Object source,String homeworkId,String paperId,
String creatorId,String creatorName,String title,UserVo userVo) {
super(source);
this.homeworkId = homeworkId;
this.paperId = paperId;
this.creatorId = creatorId;
this.userVo = userVo;
this.creatorName=creatorName;
this.title = title;
}
}
实现异步进行监听
@EventListener
@Async
public void publishHomeworkEvent(PublishHomeworkEvent event){
try {
log.info("监听发布作业事件开始: homeworkId:"+event.getHomeworkId());
// ...
}
}