事件传播
ApplicationContext 基于 Observer模式(java.util包中有对应实现),提供了针对 Bean 的事件传播功能。通过 Application.publishEvent 方法,我们可以将事件通知系统内所有的 ApplicationListener。

事件传播的一个典型应用是,当 Bean 中的操作发生异常(如数据库连接失败),则通过事件传播机制通知异常监听器进行处理。在笔者的一个项目中,就曾经借助事件机制,较好的实现了当系统异常时在监视终端上报警,同时发送报警SMS至管理员手机的功能。

ApplicationContext 容器提供了容器内部事件发布功能,是继承自JavaSE标准自定义事件类而实现的。
JavaSE标准自定义事件结构不在此详细描述,一张图很直观的描述清楚:
spring applicationContext 事件监听 - 图1

  • EventObject,为 JavaSE 提供的事件类型基类,任何自定义的事件都继承自该类,例如上图中右侧灰色的各个事件。Spring 中提供了该接口的子类 ApplicationEvent
  • EventListener 为 JavaSE 提供的事件监听者接口,任何自定义的事件监听者都实现了该接口,如上图左侧的各个事件监听者。Spring 中提供了该接口的子类 ApplicationListener 接口。
  • JavaSE 中未提供事件发布者这一角色类,由各个应用程序自行实现事件发布者这一角色。Spring 中提供了 ApplicationEventPublisher 接口作为事件发布者,并且 **ApplicationContext** 实现了这个接口,担当起了事件发布者这一角色。但 ApplicationContext 在具体实现上有所差异,Spring 提供了 ApplicationEventMulticaster 接口,负责管理 ApplicationListener 和发布 ApplicationEvent。
  • ApplicationContext 会把相应的事件相关工作委派给 ApplicationEventMulticaster 接口实现类来做。类图如下所示:spring applicationContext 事件监听 - 图2


    事件发布时序图如下:

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

项目实例

进行发布

  1. @Autowired private ApplicationContext context;
  2. PublishHomeworkEvent event = new PublishHomeworkEvent(this,homeworkId,paperId,creatorId,creatorName,title,userVo);
  3. context.publishEvent(event);

自定义发布事件

  1. @Data
  2. public class PublishHomeworkEvent extends ApplicationEvent {
  3. //作业id
  4. private String homeworkId;
  5. //作业对应的paperId
  6. private String paperId;
  7. //用户id
  8. private String creatorId;
  9. //用户名
  10. private String creatorName;
  11. //标题
  12. private String title;
  13. //用户对象(此参数中必要参数为机构code,apiKey,第三方用户id,教研云用户id)
  14. private UserVo userVo;
  15. public PublishHomeworkEvent(Object source) {
  16. super(source);
  17. }
  18. public PublishHomeworkEvent(Object source,String homeworkId,String paperId,
  19. String creatorId,String creatorName,String title,UserVo userVo) {
  20. super(source);
  21. this.homeworkId = homeworkId;
  22. this.paperId = paperId;
  23. this.creatorId = creatorId;
  24. this.userVo = userVo;
  25. this.creatorName=creatorName;
  26. this.title = title;
  27. }
  28. }

实现异步进行监听

  1. @EventListener
  2. @Async
  3. public void publishHomeworkEvent(PublishHomeworkEvent event){
  4. try {
  5. log.info("监听发布作业事件开始: homeworkId:"+event.getHomeworkId());
  6. // ...
  7. }
  8. }