五个人在报社订阅了报纸。报社一旦有了新报纸,就派员工分别送到这五个人手里。在这个例子中,“报纸”就是事件,“报社”就是广播器,五个订阅者就是监听器。广播器收到事件,把事件传给监听器,监听器对事件做一些事情。这样的例子属于观察者模式。
- 观察者模式:A类负责接收新信息,B、C、D类一直关注着A。A类一旦有了新信息,就发送给B、C、D类,B、C、D类收到信息作出不同的操作。这就是观察者模式。具体到代码中,A中设置一个变量message(这就是信息),当message改变时,调用B、C、D的performMessage(message)方法(这就把message发送给B、C、D类并让B、C、D类开始处理了。)在这里,B、C、D类是倾听者(相当于监听器),而A是发布者(相当于广播器),message就是事件。
- java的观察者模式:java.util.Observer属于倾听者接口,编写自己的倾听者只需要实现此接口。java.util.Observable是发布者,编写自己的发布者需要扩展此类。
- 事件体系:有下面几个要素:
- 事件:像新报纸一样,发生了事情,这个事情就是事件。
- 事件源:事情的发起者。
- 事件广播器:把事件通知给事件监听器。(类似报社)。
- 事件监听器:接收事件并针对事件做一些工作。(订阅者分别读了报纸后有不同的反应)。
- 事件监听器注册表:框架的事件监听器都存放在注册表里。
- 事件体系角色图:,事件源产生事件,把事件传给事件广播器,事件广播器再把事件传给事件监听器注册表中的事件监听器。
- Spring是如何使用事件广播器发布事件的?
- 要发布事件,必须有几个要素:事件类、广播器、监听器。
- java.util.EventObject是java的事件类,spring的ApplicationContextEvent扩展了EventObject类。继承关系是:,其中,ApplicationEvent继承了EventObject。我们写自己的spring事件类,可以扩展ApplicationEvent。
- java.util.EventListener是java的事件监听器类,spring的ApplicationListener扩展了EventListener接口。可以扩展ApplicationListener来编写自己的监听器(写好后在配置文件中配置)。
- spring的事件广播器继承关系:事件监听器注册表由事件广播器提供。可以实现ApplicationEventMulticaster写自己的广播器,如果没有自己的广播器,spring将使用默认的SimpleApplicationEventMulticaster广播器。 事件类、监听器类、广播器类都具备了,再写一个事件源类(制造事件,必须实现ApplicationContextAware接口,覆盖setApplicationContext方法,从而获取ApplicationContext实例。写好后在配置文件中配置),让整个事件过程运作起来。具体运作过程:
- spring容器启动时会初始化事件广播器,同时事件广播器提供了监听器注册表。
- spring根据配置文件获取所有监听器并放到监听器注册表中。
- spring容器启动完成后运行事件源类,制造事件,并把事件传给广播器,广播器再把事件传给监听器。
- 一个实例:
- 编写事件类:
public class MailSendEvent extends ApplicationContextEvent { private String to; public MailSendEvent(ApplicationContext source, String to) { super(source); this.to = to; } public String getTo() { return this.to; } }
- 编写事件监听器类:
public class MailSendListener implements ApplicationListener<MailSendEvent>{ public void onApplicationEvent(MailSendEvent event) { MailSendEvent mse = (MailSendEvent) event; System.out.println("MailSendListener:向" + mse.getTo() + "发送完一封邮件"); } }
- 编写事件源类(spring容器启动后加载该类驱动整个事件传送过程)(下面代码中,在publishEvent(mse)内部,spring委托ApplicationEventMulticaster广播器将事件通知给监听器):
public class MailSender implements ApplicationContextAware { private ApplicationContext ctx ; public void setApplicationContext(ApplicationContext ctx) throws BeansException { this.ctx = ctx; } public void sendMail(String to){ System.out.println("MailSender:模拟发送邮件..."); MailSendEvent mse = new MailSendEvent(this.ctx,to); ctx.publishEvent(mse); } }
- 在XML中配置监听器和事件源类:
<bean class="com.baobaotao.event.MailSendListener"/> <bean id="mailSender" class="com.baobaotao.event.MailSender"/>
- 主函数中调用事件源:
public static void main(String[] args) { String resourceFile = "com/baobaotao/event/beans.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(resourceFile); MailSender mailSender = ctx.getBean(MailSender.class); mailSender.sendMail("test mail."); System.out.println("done."); }
- 编写事件类: