Spring源碼之七registerListeners()及發(fā)布訂閱模式

Spring源碼之七registerListeners()及發(fā)布訂閱模式

大家好,我是程序員田同學(xué)。

今天帶大家解讀refresh()方法中的registerListeners()方法,也就是我們經(jīng)常說的Spring的發(fā)布-訂閱模式。文章首先舉一個(gè)發(fā)布-訂閱模式的樣例,然后講解了發(fā)布-訂閱四個(gè)模式的原理,及對(duì)發(fā)布-訂閱模式所依賴的觀察者模式進(jìn)行了舉例,最后引出該模式在Springboot中的大量應(yīng)用。

照例放一份refresh()方法的源碼,registerListeners()方法位于該方法的第七個(gè)位置。

@Override

public void refresh() throws BeansException, IllegalStateException {

? synchronized (this.startupShutdownMonitor) {

? ?? // Prepare this context for refreshing.

? ?? //1、刷新前的準(zhǔn)備

? ?? prepareRefresh();

? ?? // Tell the subclass to refresh the internal bean factory.

? ?? //2、將會(huì)初始化 BeanFactory、加載 Bean、注冊(cè) Bean

? ?? ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

? ?? // Prepare the bean factory for use in this context.

? ?? //3、設(shè)置 BeanFactory 的類加載器,添加幾個(gè) BeanPostProcessor,手動(dòng)注冊(cè)幾個(gè)特殊的 bean

? ?? prepareBeanFactory(beanFactory);

? ?? try {

? ? ? ? //4、模板方法

? ? ? ? // Allows post-processing of the bean factory in context subclasses.

? ? ? ? postProcessBeanFactory(beanFactory);

? ? ? ? // Invoke factory processors registered as beans in the context.

? ? ? ? //執(zhí)行BeanFactory后置處理器

? ? ? ? invokeBeanFactoryPostProcessors(beanFactory);

? ? ? ? // 5、Register bean processors that intercept bean creation.

? ? ? ? //注冊(cè)bean后置處理器

? ? ? ? registerBeanPostProcessors(beanFactory);

? ? ? ? // Initialize message source for this context.

? ? ? ? //國(guó)際化

? ? ? ? initMessageSource();

? ? ? ? // Initialize event multicaster for this context.

? ? ? ? initApplicationEventMulticaster();

? ? ? ? // Initialize other special beans in specific context subclasses.

? ? ? ? //6、模板方法--springboot實(shí)現(xiàn)了這個(gè)方法

? ? ? ? onRefresh();

? ? ? ? // Check for listener beans and register them.

? ? ? ? //7、注冊(cè)監(jiān)聽器

? ? ? ? registerListeners();

? ? ? ? // Instantiate all remaining (non-lazy-init) singletons.

? ? ? ? //8、完成bean工廠的初始化**方法重要**********************************************

? ? ? ? finishBeanFactoryInitialization(beanFactory);

? ? ? ? //9、 Last step: publish corresponding event.

? ? ? ? finishRefresh();

? ?? }

? ?? catch (BeansException ex) {

? ? ? ? if (logger.isWarnEnabled()) {

? ? ? ? ?? logger.warn("Exception encountered during context initialization - " +

? ? ? ? ? ? ? ?? "cancelling refresh attempt: " + ex);

? ? ? ? }

? ? ? ? // Destroy already created singletons to avoid dangling resources.

? ? ? ? destroyBeans();

? ? ? ? // Reset 'active' flag.

? ? ? ? cancelRefresh(ex);

? ? ? ? // Propagate exception to caller.

? ? ? ? throw ex;

? ?? }

先大致看一下registerListeners()方法的源碼。

protected void registerListeners() {

? ? ? ? // Register statically specified listeners first.

? ? ? ? // 首先注冊(cè)靜態(tài)的指定的監(jiān)聽器,注冊(cè)的是特殊的事件監(jiān)聽器,而不是配置中的bean

? ? ? ? for (ApplicationListener listener : getApplicationListeners()) {

? ? ? ? ? ? getApplicationEventMulticaster().addApplicationListener(listener);

? ? ? ? }

? ? ? ? // Do not initialize FactoryBeans here: We need to leave all regular beans

? ? ? ? // uninitialized to let post-processors apply to them!

? ? ? ? // 這里不會(huì)初始化FactoryBean,我們需要保留所有的普通bean

? ? ? ? // 不會(huì)實(shí)例化這些bean,讓后置處理器可以感知到它們

? ? ? ? String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);

? ? ? ? for (String listenerBeanName : listenerBeanNames) {

? ? ? ? ? ? getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

? ? ? ? }

? ? ? ? // Publish early application events now that we finally have a multicaster...

? ? ? ? // 現(xiàn)在有了事件廣播組,發(fā)布之前的應(yīng)用事件

? ? ? ? Set earlyEventsToProcess = this.earlyApplicationEvents;

? ? ? ? this.earlyApplicationEvents = null;

? ? ? ? if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {

? ? ? ? ? ? for (ApplicationEvent earlyEvent : earlyEventsToProcess) {

? ? ? ? ? ? ? ? getApplicationEventMulticaster().multicastEvent(earlyEvent);

? ? ? ? ? ? }

? ? ? ? }

? ? }

這個(gè)方法要做的很簡(jiǎn)單,就是兩個(gè)循環(huán)遍歷,把Spring通過硬編碼定義的監(jiān)聽器注冊(cè)到容器中,然后把我們自定義的監(jiān)聽器注冊(cè)到容器中,通過這些直接敘述有一些蒼白無力,我們寫一個(gè)簡(jiǎn)單的發(fā)布-訂閱的例子方便理解。

在發(fā)布訂閱模式用需要四個(gè)角色:

ApplicationEvent:事件,每個(gè)實(shí)現(xiàn)類表示一類事件,可攜帶數(shù)據(jù)。抽象類。ApplicationListener:事件監(jiān)聽器,用于接收事件處理時(shí)間。接口。ApplicationEventMulticaster:事件管理者,可以注冊(cè)(添加)/移除/發(fā)布事件。用于事件監(jiān)聽器的注冊(cè)和事件的廣播。接口。ApplicationEventPublisher:事件發(fā)布者,委托事件管理者ApplicationEventMulticaster完成事件發(fā)布。

事件:

@Component

public class MyEvent extends ApplicationEvent {

? ? private static final long serialVersionUID = 1L;


? ? /**

? ? * Create a new ApplicationEvent.

? ? *

? ? * @param source the object on which the event initially occurred (never {@code null})

? ? */

? ? public MyEvent(Object source) {

? ? ? ? super(source);

? ? }

}

事件監(jiān)聽器:

@Component

public class MyEventListener implements ApplicationListener<MyEvent> {

? ? @EventListener //@EventListener注解實(shí)現(xiàn)事件監(jiān)聽

? ? @Override

? ? public void onApplicationEvent(MyEvent event) {

? ? ? ? Object msg = event.getSource();

? ? ? ? System.out.println("自定義事件監(jiān)聽器(MyEventListener1)收到發(fā)布的消息: " + msg);

? ? }

}

事件發(fā)布者:

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);

? ? }

那么事件的管理器跑哪去了呢?

我們?cè)?registerListeners()方法上面打一個(gè)斷點(diǎn),看看我們自定義的事件是如何在Spring中起作用的。

第一個(gè)循環(huán)是Spring默認(rèn)的監(jiān)聽器默認(rèn)情況下是空。

我們自定義的事件監(jiān)聽器在第二個(gè)循環(huán)里面被加載到了ApplicationEventMulticaster中,已經(jīng)很明顯了,ApplicationEventMulticaster就是我們的事件管理者。

我們?cè)诎阉麄冎g的關(guān)系詳細(xì)串一下。

注:廣播器和上面的管理者是一個(gè)意思

到這個(gè)階段,事件管理者和監(jiān)聽器都在Spring容器里初始化和注冊(cè)了,之后就可以實(shí)現(xiàn)監(jiān)聽者模式了,對(duì)事件的發(fā)布進(jìn)行監(jiān)聽然后處理。

在就是ac.publishEvent(myEvent);方法發(fā)布事件后進(jìn)行的業(yè)務(wù)處理。

ApplicationContext ac =new AnnotationConfigApplicationContext(MyEventListener.class);

? ? ? ? MyEvent myEvent=new MyEvent(new Object());

? ? ? ? ac.publishEvent(myEvent);

事件監(jiān)聽機(jī)制實(shí)際就是主題-訂閱模式(觀察者模式)的實(shí)現(xiàn),能夠降低代碼耦合。

本文順便把觀察者模式簡(jiǎn)要的敘述一下,方便讀者可以更好的理解。

觀察者(Observer)模式的定義:指多個(gè)對(duì)象間存在一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新。

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);

?? }

}

//抽象目標(biāo):匯率

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);

}

//具體目標(biāo):人民幣匯率

class RMBrate extends Rate {

?? public void change(int number) {

? ? ?? for (Company obs : companys) {

? ? ? ? ?? ((Company) obs).response(number);

? ? ?? }

?? }

}

//抽象觀察者:公司

interface Company {

?? void response(int number);

}

//具體觀察者1:進(jìn)口公司

class ImportCompany implements Company {

?? public void response(int number) {

? ? ?? if (number > 0) {

? ? ? ? ?? System.out.println("人民幣匯率升值" + number + "個(gè)基點(diǎn),降低了進(jìn)口產(chǎn)品成本,提升了進(jìn)口公司利潤(rùn)率。");

? ? ?? } else if (number < 0) {

? ? ? ? ?? System.out.println("人民幣匯率貶值" + (-number) + "個(gè)基點(diǎn),提升了進(jìn)口產(chǎn)品成本,降低了進(jìn)口公司利潤(rùn)率。");

? ? ?? }

?? }

}

//具體觀察者2:出口公司

class ExportCompany implements Company {

?? public void response(int number) {

? ? ?? if (number > 0) {

? ? ? ? ?? System.out.println("人民幣匯率升值" + number + "個(gè)基點(diǎn),降低了出口產(chǎn)品收入,降低了出口公司的銷售利潤(rùn)率。");

? ? ?? } else if (number < 0) {

? ? ? ? ?? System.out.println("人民幣匯率貶值" + (-number) + "個(gè)基點(diǎn),提升了出口產(chǎn)品收入,提升了出口公司的銷售利潤(rùn)率。");

? ? ?? }

?? }

}

匯率變化就是一個(gè)事件,當(dāng)該事件發(fā)生時(shí),它的觀察者出口公司和進(jìn)口公司就要做相應(yīng)的變化。

書歸正傳重新回到registerListeners()方法中,這時(shí)所有的監(jiān)聽器都注冊(cè)到了容器中,只等publishEvent()發(fā)布事件以后,就會(huì)執(zhí)行我們監(jiān)聽器中的業(yè)務(wù)邏輯。

據(jù)說在Springboot中應(yīng)用了大量的發(fā)布訂閱模式,抱著求知若渴的態(tài)度我們?nèi)pringboot中摟一眼,在registerListeners()上面打一個(gè)斷點(diǎn),看看和Spring上面的斷點(diǎn)有什么區(qū)別。

在Spirng中監(jiān)聽器默認(rèn)是空,當(dāng)時(shí)在Springboot中有15個(gè)之多,不愧是加強(qiáng)版的Spring。具體這些監(jiān)聽器是干嘛的我們就不深究了,在Springboot中會(huì)對(duì)其逐步拆解的。

好啦,今天對(duì)registerListeners()的方法的剖析也就結(jié)束啦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容