SpringFramework的事件机制

观察者模式 观察者模式的定义:多个对象间存在一对多依赖关系,当其中一个对象状态发生变化时,所有依赖于它的对象都要得到通知并作出相应处理。
【SpringFramework的事件机制】其中被依赖的对象为目标对象,或事件源,其他对象称为观察者,目标对象的状态变化称为事件。
观察者模式的适用场景 具体的观察者对象不明确,或者在编码阶段不明确。
实现方式 抽象主题(subject)或者抽象目标类,提供增加、移除观察者对象的方法,以及通知所有观察者的方法。
具体主题(concrete subject)或者目标实现类,实现抽象目标的所有抽象方法。
观察者(Observer)接口,提供一个接收通知的方法,当接收到主题的通知方法后被调用。
具体观察者(Concrete Observer),观察者接口的实现类。
我们可以在代码中根据以上结构快速实现一个观察者模式的简单应用,JDK也提供了观察者模式的实现,但是今天我们主要探讨Spring Framework的实现方式,所以,对前者不做探讨。
Spring Framework对观察者模式的实现 为方便程序员调用,Spring提供了现成的观察者模式,所以程序员不再需要自己写代码实现观察者模式,在Spring中只需要简单几步即可实现。
Spring提供了以下几个组件:

  1. ApplicationEvent:事件抽象类,通过扩展此类实现用户事件。
  2. ApplicationEventPublisherAware:事件发布器接口,用户的目标类通过实现该接口、通过Spring框架完成事件发布。
  3. ApplicationListener 观察者(监听器)接口,用户通过该接口实现对事件发布器发布的ApplicationEvent事件的监听,该接口只有一个方法:void onApplicationEvent(E event),该方法有Spring容器在接收到事件发布器发布的对应事件后调用。
  4. @EventListener:通过注解方式实现的观察者(监听器),作用及效果同ApplicationListener接口
具体实现 最简单有效的解释莫过于举例,下面举例说明Spring事件机制的具体实现方式。
我们先假设一个场景:用户类userService有一个用户注册的方法userRegister,注册成功后我们需要通过短信、微信等不同的方式给相关方发通知。
  1. 按照Spring事件机制的实现方式,我们首先需要定义用户注册事件:
public class userRegisterEvent extends ApplicationEvent { private userService userService; /** * Create a new {@code ApplicationEvent}. * * @param source the object on which the event initially occurred or with *which the event is associated (never {@code null}) */ // 通过实现ApplicationEvent接口,创建一个事件 public userRegisterEvent(Object source) { super(source); this.userService = (userService) source; } }

  1. userService类是用户服务类,按照上述约定,userService类提供一个用户注册的方法。因为我们需要在用户注册成功后发布通知,所以,userService需要具备事件发布的能力,需要实现ApplicationEventPublisherAware接口:
@Component @Slf4j public class userService implements ApplicationEventPublisherAware { //定义事件发布器 ApplicationEventPublisher publisher; public String name; //默认是单例bean,在容器初始化的时候就会被创建、初始化 public userService(){ System.out.println("userService constructed。。。"); }//自定义的事件发布方法,与应用进行绑定,在应用某一特定事件完成后,通过容器的事件发布器将事件发布到容器中 public void userRegister(String userName){ log.info("User register sucessful") ; this.setName(userName); publisher.publishEvent(new userRegisterEvent(this)); }//实现事件发布器的方法,获取到容器中的事件发布器 @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.publisher=applicationEventPublisher; }public String getName(){ return this.name; }public void setName(String name){ this.name=name; } }

  1. 剩下的就是要实现观察者了,由以上的介绍我们知道Spring有两种方式实现观察者,首先通过ApplicationListener的方式实现观察者。为了简化逻辑,监听到用户事件之后我们只是简单打印一下即可:
@Component @Slf4j public class UserReigisterListener implements ApplicationListener {//通过实现接口ApplicationListener,监听容器中发布的特定事件 @Override public void onApplicationEvent(userRegisterEvent event) { userServiceuser = (userService)event.getSource(); if (user != null){ log.info("I have a message from userService:" + user.getName()); } } }

  1. 通过注解方式实现监听者:
@Component @Slf4j public class SmsSendListener {@EventListener @Order(0) public void onRegister(userRegisterEvent event){ userServiceuser = (userService)event.getSource(); if (user != null){ log.info("I will send SMS to :" + user.getName()); } } }

完成了,可以测试了。
编写启动类,测试:
@Slf4j public class App {public static void main( String[] args ) { ApplicationContext ctx=new AnnotationConfigApplicationContext(commonConfig.class); //获取userService实例 userService us=ctx.getBean("userService",userService.class); us.userRegister("Zhang san"); } }

运行:
22:50:33.538 [main] INFO org.example.service.SmsSendListener - I will send SMS to :Zhang san 22:50:33.538 [main] INFO org.example.service.UserReigisterListener - I have a message from userService:Zhang san

从打印结果可以看到,userService类的方法userRegister通过调用Spring框架的事件发布器,将用户 Zhang san的注册成功的信息通知给了两个监听器(观察者)。
这样我们就采用非常简单的方式、通过Spring框架实现了观察者模式,将用户注册成功的消息传递给了观察者,不同的观察者可以根据业务要求做出不同的响应。
而且,不管是通过实现接口、还是采用注解,我们都可以非常方便的注册多个观察者,比如我们可以快速实现一个微信通知的观察者、邮件通知的观察者等等。
关键是,增加观察者不需要和事件源(目标类,比如上述案例的用户服务类)发生任何耦合,不需要对目标类做出任何改动。
Spring框架事件机制的原理后续分析。

    推荐阅读