Spring源码之七registerListeners()及发布订阅模式
大家好,我是程序员田同学。
今天带大家解读refresh()方法中的registerListeners()方法,也就是我们经常说的Spring的发布-订阅模式。文章首先举一个发布-订阅模式的样例,然后讲解了发布-订阅四个模式的原理,及对发布-订阅模式所依赖的观察者模式进行了举例,最后引出该模式在Springboot中的大量应用。
照例放一份refresh()方法的源码,registerListeners()方法位于该方法的第七个位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { prepareRefresh() ; ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory() ; prepareBeanFactory(beanFactory ) ; try { postProcessBeanFactory(beanFactory ) ; invokeBeanFactoryPostProcessors(beanFactory ) ; registerBeanPostProcessors(beanFactory ) ; initMessageSource() ; initApplicationEventMulticaster() ; onRefresh() ; registerListeners() ; finishBeanFactoryInitialization(beanFactory ) ; finishRefresh() ; } catch (BeansException ex) { if (logger.isWarnEnabled() ) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans() ; cancelRefresh(ex ) ; throw ex; }
先大致看一下registerListeners()方法的源码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 protected void registerListeners() { for (ApplicationListener<?> listener : getApplicationListeners() ) { getApplicationEventMulticaster() .addApplicationListener(listener ) ; } String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class , true , false ) ; for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster() .addApplicationListenerBean(listenerBeanName ) ; } Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (!CollectionUtils . isEmpty(earlyEventsToProcess ) ) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster() .multicastEvent(earlyEvent ) ; } } }
这个方法要做的很简单,就是两个循环遍历,把Spring通过硬编码定义的监听器注册到容器中,然后把我们自定义的监听器注册到容器中,通过这些直接叙述有一些苍白无力,我们写一个简单的发布-订阅的例子方便理解。
在发布订阅模式用需要四个角色:
ApplicationEvent:事件,每个实现类表示一类事件,可携带数据。抽象类。 ApplicationListener:事件监听器,用于接收事件处理时间。接口。 ApplicationEventMulticaster:事件管理者,可以注册(添加)/移除/发布事件。用于事件监听器的注册和事件的广播。接口。 ApplicationEventPublisher:事件发布者,委托事件管理者ApplicationEventMulticaster完成事件发布。
事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Component public class MyEvent extends ApplicationEvent { private static final long serialVersionUID = 1 L; public MyEvent (Object source) { super (source); } }
事件监听器:
1 2 3 4 5 6 7 8 9 10 11 @Component public class MyEventListener implements ApplicationListener <MyEvent > { @EventListener @Override public void onApplicationEvent (MyEvent event ) { Object msg = event.getSource (); System .out .println ("自定义事件监听器(MyEventListener1)收到发布的消息: " + msg); } }
事件发布者:
1 2 3 4 5 6 7 public static void main (String [] args ) { System .out .println (1 ); ApplicationContext ac =new AnnotationConfigApplicationContext (MyEventListener .class ); MyEvent myEvent=new MyEvent (new Object ()); ac.publishEvent (myEvent); }
那么事件的管理器跑哪去了呢?
我们在 registerListeners()方法上面打一个断点,看看我们自定义的事件是如何在Spring中起作用的。
第一个循环是Spring默认的监听器默认情况下是空。
我们自定义的事件监听器在第二个循环里面被加载到了ApplicationEventMulticaster中,已经很明显了,ApplicationEventMulticaster就是我们的事件管理者。
我们在把他们之间的关系详细串一下。
注:广播器和上面的管理者是一个意思
到这个阶段,事件管理者和监听器都在Spring容器里初始化和注册了,之后就可以实现监听者模式了,对事件的发布进行监听然后处理。
在就是ac.publishEvent(myEvent);方法发布事件后进行的业务处理。
1 2 3 ApplicationContext ac =new AnnotationConfigApplicationContext(MyEventListener.class ) ; MyEvent myEvent=new MyEvent(new Object() ); ac.publishEvent(myEvent ) ;
事件监听机制实际就是主题-订阅模式(观察者模式)的实现,能够降低代码耦合。
本文顺便把观察者模式简要的叙述一下,方便读者可以更好的理解。
观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public class RMBrateTest { public static void main (String [] args ) { Rate rate = new RMBrate (); Company watcher1 = new ImportCompany (); Company watcher2 = new ExportCompany (); rate.add (watcher1); rate.add (watcher2); rate.change (10 ); rate.change (-9 ); } }abstract class Rate { protected List <Company > companys = new ArrayList <Company >(); public void add (Company company ) { companys.add (company); } public void remove (Company company ) { companys.remove (company); } public abstract void change (int number ); }class RMBrate extends Rate { public void change (int number ) { for (Company obs : companys) { ((Company ) obs).response (number ); } } }interface Company { void response (int number ); }class ImportCompany implements Company { public void response (int number ) { if (number > 0 ) { System .out .println ("人民币汇率升值" + number + "个基点,降低了进口产品成本,提升了进口公司利润率。" ); } else if (number < 0 ) { System .out .println ("人民币汇率贬值" + (-number ) + "个基点,提升了进口产品成本,降低了进口公司利润率。" ); } } }class ExportCompany implements Company { public void response (int number ) { if (number > 0 ) { System .out .println ("人民币汇率升值" + number + "个基点,降低了出口产品收入,降低了出口公司的销售利润率。" ); } else if (number < 0 ) { System .out .println ("人民币汇率贬值" + (-number ) + "个基点,提升了出口产品收入,提升了出口公司的销售利润率。" ); } } }
汇率变化就是一个事件,当该事件发生时,它的观察者出口公司和进口公司就要做相应的变化。
书归正传重新回到registerListeners()方法中,这时所有的监听器都注册到了容器中,只等publishEvent()发布事件以后,就会执行我们监听器中的业务逻辑。
据说在Springboot中应用了大量的发布订阅模式,抱着求知若渴的态度我们去Springboot中搂一眼,在registerListeners()上面打一个断点,看看和Spring上面的断点有什么区别。
在Spirng中监听器默认是空,当时在Springboot中有15个之多,不愧是加强版的Spring。具体这些监听器是干嘛的我们就不深究了,在Springboot中会对其逐步拆解的。
好啦,今天对registerListeners()的方法的剖析也就结束啦。
安利时刻: