当前位置: 首页 > 后端技术 > Java

Spring源码七registerListeners()及发布订阅模式

时间:2023-04-01 22:59:51 Java

Spring源码七registerListeners()及发布订阅模式大家好,我是田程序员。今天就带大家解读一下refresh()方法中的registerListeners()方法,也就是我们常说的Spring的发布-订阅模型。文章首先给出了发布-订阅模型的例子,然后讲解了发布-订阅四种模型的原理,并给出了发布-订阅模型所依赖的观察者模型的例子,最后引出大量的该模型在Springboot中的应用。照例放一个refresh()方法的源码,registerListeners()方法位于方法的第七个位置。@Overridepublicvoidrefresh()throwsBeansException,IllegalStateException{synchronized(this.startupShutdownMonitor){//准备此上下文以进行刷新。//1。刷新前准备prepareRefresh();//告诉子类刷新内部bean工厂。//2、会初始化BeanFactory,加载Bean,注册BeanConfigurableListableBeanFactorybeanFactory=obtainFreshBeanFactory();//准备在此上下文中使用的bean工厂。//3、设置BeanFactory的类加载器,添加几个BeanPostProcessor,手动注册几个特殊的beanprepareBeanFactory(beanFactory);try{//4,模板方法//允许在上下文子类中对bean工厂进行后处理。postProcessBeanFactory(beanFactory);//调用在上下文中注册为bean的工厂处理器。//执行BeanFactory后处理器invokeBeanFactoryPostProcessors(beanFactory);//5.注册拦截bean创建的bean处理器。//注册bean后处理器注册BeanPostProcessors(beanFactory);//为这个上下文初始化消息源。//国际化initMessageSource();//为此上下文初始化事件多播器。initApplicationEventMulticaster();//初始化特定上下文子类中的其他特殊bean。//6。模板方法——springboot实现了该方法onRefresh();//检查侦听器bean并注册它们。//7。注册监听器registerListeners();//实例化所有剩余的(非惰性初始化)单例。//8.完成bean工厂的初始化**方法很重要************************************************finishBeanFactoryInitialization(beanFactory);//9、最后一步:发布相应的事件。完成刷新();}catch(BeansExceptionex){if(logger.isWarnEnabled()){logger.warn("上下文初始化时遇到异常-"+"取消刷新attempt:"+ex);}//销毁已经创建的单例以避免悬空资源。destroyBeans();//重置'active'标志。cancelRefresh(ex);//将异常传播给调用者。throwex;看看registerListeners()方法的源代码protectedvoidregisterListeners(){//首先注册静态指定的监听器。//先注册静态指定的监听器,这是一个特殊的事件监听器,不是配置中的bean}//不要在此处初始化FactoryBeans:我们需要保留所有常规beans//未初始化以让后处理器应用于它们!//这里不会初始化FactoryBean,我们需要保留所有的普通bean//这些bean不会被实例化,以便后处理器感知它们String[]listenerBeanNames=getBeanNamesForType(ApplicationListener.class,true,false);for(StringlistenerBeanName:listenerBeanNames){getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}//现在我们终于有了一个多播器,发布早期应用程序事件...//现在我们有了一个事件广播组,我们可以发布以前的应用程序事件SetearlyEventsToProcess=this.earlyApplicationEvents;this.earlyApplicationEvents=null;如果(!CollectionUtils.isEmpty(earlyEventsToProcess)){for(ApplicationEventearlyEvent:earlyEventsToProcess){getApplicationEventMulticaster().multicastEvent(earlyEvent);这个方法很简单,就是两次循环遍历,将Spring硬编码定义的监听器注册到容器中,再将我们自定义的监听器注册到容器中。通过这些直接的描述,有些苍白,我们来写一个简单的发布-订阅的例子,很容易理解发布-订阅模式需要四个角色:ApplicationEvent:事件,每个实现类代表一类事件和可以携带数据。抽象类。ApplicationListener:事件监听器,用于接收事件处理时间。界面。ApplicationEventMulticaster:一个可以注册(添加)/删除/发布事件的事件管理器。用于事件监听器注册和事件广播。界面。ApplicationEventPublisher:事件发布者,委托事件管理器ApplicationEventMulticaster完成事件发布。事件:@ComponentpublicclassMyEventextendsApplicationEvent{privatestaticfinallongserialVersionUID=1L;/***创建一个新的应用程序事件。**@paramsource事件最初发生的对象(永远不会{@codenull})*/publicMyEvent(Objectsource){super(source);}}事件监听:@ComponentpublicclassMyEventListenerimplementsApplicationListener{@EventListener//@EventListener注解实现事件监听@OverridepublicvoidonApplicationEvent(MyEventevent){Objectmsg=event.getSource();System.out.println("自定义事件监听器(MyEventListener1)收到发布的消息:"+msg);}}事件发布者:publicstaticvoidmain(String[]args){System.out.println(1);ApplicationContextac=newAnnotationConfigApplicationContext(MyEventListener.class);MyEventmyEvent=newMyEvent(newObject());ac.publishEvent(我的事件);那么事件管理器去哪儿了?让我们在registerListeners()方法上放置一个断点,看看我们是否自定义事件在Spring中如何工作的第一个循环是Spring的默认侦听器默认为空。我们的自定义事件监听器在第二个循环中被加载到ApplicationEventMulticaster中,很明显ApplicationEventMulticaster是我们的事件管理器。让我们详细看看它们之间的关系。注:上面的主播和经理是一个意思。在这个阶段,事件管理器和监听器都被初始化并注册到Spring容器中,然后可以实现监听器模式来监听和处理事件发布。是ac.publishEvent(myEvent)发布事件后的业务处理;方法。ApplicationContextac=newAnnotationConfigApplicationContext(MyEventListener.class);MyEventmyEvent=newMyEvent(newObject());ac.publishEvent(我的事件);事件监听机制实际上是subject-subscription模式(观察者模式)的实现,可以降低代码耦合。本文顺便简单介绍下观察者模式,方便读者更好的理解。观察者(Observer)模式的定义:指多个对象之间存在一对多的依赖关系。当一个对象的状态发生变化时,所有依赖它的对象都会收到通知并自动更新。公共类RMBrateTest{publicstaticvoidmain(String[]args){Raterate=newRMBrate();公司watcher1=newImportCompany();公司watcher2=newExportCompany();rate.add(watcher1);rate.add(watcher2);汇率变化(10);汇率变化(-9);}}//抽象对象:汇率抽象类Rate{protectedListcompanies=newArrayList();//添加观察者方法publicvoidadd(Companycompany){companys.add(company);}//移除观察者方法publicvoidremove(Companycompany){companys.remove(company);}publicabstractvoidchange(intnumber);}//具体目标:人民币汇率类RMBrateextendsRate{publicvoidchange(intnumber){for(Companyobs:companies){((Company)obs).response(number);}}}//抽象观察者:companyinterfaceCompany{voidresponse(intnumber);}//具体观察者1:importcompanyclassImportCompanyimplementsCompany{publicvoidresponse(intnumber){if(number>0){System.out.println("人民币汇率升值"+number+"基点,降低了进口产品的成本,提高了进口企业的利润率");}elseif(number<0){System.out.println("人民币汇率贬值"+(-number)+"基点,增加了进口产品的成本,降低了进口企业的利润率。");}}}//具体观察者2:出口公司类ExportCompanyimplementsCompany{publicvoidresponse(intnumber){if(number>0){System.out.println("人民币汇率升值"+number+"基点,降低了出口产品的收入,降低了出口企业的销售利润率。”);}elseif(number<0){System.out.println("人民币汇率贬值"+(-number)+"一个基点,增加了出口产品的收入和出口企业的销售利润率。");}}}汇率变化是一个事件。当事件发生时,其观察者即出口公司和进口公司将做出相应的改变。言归正传,回到registerListeners()方法,此时所有的监听器都注册到了容器中,只有publishEvent()发布事件后,我们的监听器中的业务逻辑才会被执行。据说在Springboot中应用了大量的发布-订阅模型。抱着口渴的心态,我们在Springboot中看一看,在registerListeners()上设置断点,看看和Spring上的断点有什么区别。Spirng中的监听器默认为空。当时Springboot有15个之多,确实是Spring的增强版。这些监听器是做什么用的我们就不细说了,会在Springboot中逐步拆解。好了,今天对registerListeners()方法的分析就结束了。