中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

杭州下沙做網(wǎng)站的論壇網(wǎng)站建設(shè)全包

杭州下沙做網(wǎng)站的論壇,網(wǎng)站建設(shè)全包,應(yīng)用分發(fā)平臺(tái),學(xué)校部門網(wǎng)站建設(shè)情況匯報(bào)文章目錄 demo應(yīng)用實(shí)現(xiàn)基于注解事件過濾異步事件監(jiān)聽 源碼解讀總結(jié) ApplicationContext 中的事件處理是通過 ApplicationEvent 類和 ApplicationListener 接口提供的。如果將實(shí)現(xiàn)了 ApplicationListener 接口的 bean 部署到容器中,則每次將 ApplicationEvent 發(fā)布到…

文章目錄

  • demo應(yīng)用
    • 實(shí)現(xiàn)
    • 基于注解
    • 事件過濾
    • 異步事件監(jiān)聽
  • 源碼解讀
  • 總結(jié)

Spring事件ApplicationEvent源碼淺讀 - Java技術(shù)債務(wù)

ApplicationContext 中的事件處理是通過 ApplicationEvent 類和 ApplicationListener 接口提供的。如果將實(shí)現(xiàn)了 ApplicationListener 接口的 bean 部署到容器中,則每次將 ApplicationEvent 發(fā)布到ApplicationContext 時(shí),都會(huì)通知到該 bean,這簡直是典型的觀察者模式。設(shè)計(jì)的初衷就是為了系統(tǒng)業(yè)務(wù)邏輯之間的解耦,提高可擴(kuò)展性以及可維護(hù)性。

Spring 中提供了以下的事件

Event描述
ContextRefreshedEventApplicationContext 被初始化或刷新時(shí),該事件被發(fā)布。這也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法來發(fā)生
ContextStartedEvent當(dāng)使用 ConfigurableApplicationContext 接口中的 start() 方法啟動(dòng) ApplicationContext 時(shí),該事件被發(fā)布。你可以調(diào)查你的數(shù)據(jù)庫,或者你可以在接受到這個(gè)事件后重啟任何停止的應(yīng)用程序
ContextStoppedEvent當(dāng)使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 時(shí),發(fā)布這個(gè)事件。你可以在接受到這個(gè)事件后做必要的清理的工作
ContextClosedEvent使用 ConfigurableApplicationContext 接口中的 close() 方法關(guān)閉 ApplicationContext 時(shí),該事件被發(fā)布。一個(gè)已關(guān)閉的上下文到達(dá)生命周期末端;它不能被刷新或重啟
RequestHandledEvent這是一個(gè) web-specific 事件,告訴所有 bean HTTP 請(qǐng)求已經(jīng)被服務(wù)
ServletRequestHandledEventRequestHandledEvent的一個(gè)子類,用于添加特定于Servlet的上下文信息。

demo應(yīng)用

具體的詳情可以訪問:https://cuizb.top/myblog/static/resource/Untitled-1697189238408.png
這里只是個(gè)demo例子

實(shí)現(xiàn)

1、 自定義事件類,基于ApplicationEvent實(shí)現(xiàn)擴(kuò)展;

public class DemoEvent extends ApplicationEvent {private static final long serialVersionUID = -2753705718295396328L;private String msg;public DemoEvent(Object source, String msg) {super(source);this.msg = msg;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}

2、 定義Listener類,實(shí)現(xiàn)ApplicationListener接口,并且注入到IOC中等發(fā)布者發(fā)布事件時(shí),都會(huì)通知到這個(gè)bean,從而達(dá)到監(jiān)聽的效果;

@Component
public class DemoListener implements ApplicationListener<DemoEvent> {@Overridepublic void onApplicationEvent(DemoEvent demoEvent) {String msg = demoEvent.getMsg();System.out.println("bean-listener 收到了 publisher 發(fā)布的消息: " + msg);}
}

3、 要發(fā)布上述自定義的event,需要調(diào)用ApplicationEventPublisher的publishEvent方法,我們可以定義一個(gè)實(shí)現(xiàn)ApplicationEventPublisherAware的類,并注入IOC來進(jìn)行調(diào)用;

@Component
public class DemoPublisher implements ApplicationEventPublisherAware {private ApplicationEventPublisher applicationEventPublisher;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}public void sendMsg(String msg) {applicationEventPublisher.publishEvent(new DemoEvent(this, msg));}
}

4、 客戶端調(diào)用publisher;

@RestController
@RequestMapping("/event")
public class DemoClient implements ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@GetMapping("/publish")public void publish(){DemoPublisher bean = applicationContext.getBean(DemoPublisher.class);bean.sendMsg("發(fā)布者發(fā)送消息......");}
}

輸出結(jié)果:

bean-listener 收到了 publisher 發(fā)布的消息: 發(fā)布者發(fā)送消息......

基于注解

我們可以不用實(shí)現(xiàn) AppplicationListener 接口 ,在方法上使用 @EventListener 注冊(cè)事件。如果你的方法應(yīng)該偵聽多個(gè)事件,并不使用任何參數(shù)來定義,可以在 @EventListener 注解上指定多個(gè)事件。

重寫DemoListener 類如下:

public class DemoListener {@EventListener(value = {DemoEvent.class, TestEvent.class})public void processApplicationEvent(DemoEvent event) {String msg = event.getMsg();System.out.println("bean-listener 收到了 publisher 發(fā)布的消息: " + msg);}
}

事件過濾

如果希望通過一定的條件對(duì)事件進(jìn)行過濾,可以使用 @EventListener 的 condition 屬性。以下實(shí)例中只有 event 的 msg 屬性是 my-event 時(shí)才會(huì)進(jìn)行調(diào)用。

@EventListener(value = {DemoEvent.class, TestEvent.class}, condition = "#event.msg == 'my-event'")
public void processApplicationEvent(DemoEvent event) {String msg = event.getMsg();System.out.println("bean-listener 收到了 publisher 發(fā)布的消息: " + msg);}

此時(shí),發(fā)送符合條件的消息,listener 才會(huì)偵聽到 publisher 發(fā)布的消息。

bean-listener 收到了 publisher 發(fā)布的消息: my-event

異步事件監(jiān)聽

前面提到的都是同步處理事件,那如果我們希望某個(gè)特定的偵聽器異步去處理事件,如何做?

使用@Async 注解可以實(shí)現(xiàn)類內(nèi)方法的異步調(diào)用,這樣方法在執(zhí)行的時(shí)候,將會(huì)在獨(dú)立的線程中被執(zhí)行,調(diào)用者無需等待它的完成,即可繼續(xù)其他的操作。

@EventListener
@Async
public void processApplicationEvent(DemoEvent event) {String msg = event.getMsg();System.out.println("bean-listener 收到了 publisher 發(fā)布的消息: " + msg);
}

使用異步監(jiān)聽時(shí),有兩點(diǎn)需要注意:

  • 如果異步事件拋出異常,則不會(huì)將其傳播到調(diào)用方。
  • 異步事件監(jiān)聽方法無法通過返回值來發(fā)布后續(xù)事件,如果需要作為處理結(jié)果發(fā)布另一個(gè)事件,請(qǐng)插入 ApplicationEventPublisher 以手動(dòng)發(fā)布事件

源碼解讀

ApplicationEvent事件機(jī)制流程:

  1. ApplicationEventPublisher是Spring的事件發(fā)布接口,事件源通過該接口的pulishEvent方法發(fā)布事件;
  2. ApplicationEventMulticaster就是Spring事件機(jī)制中的事件廣播器,它默認(rèn)提供一個(gè)SimpleApplicationEventMulticaster實(shí)現(xiàn),如果用戶沒有自定義廣播器,則使用默認(rèn)的它通過父類AbstractApplicationEventMulticastergetApplicationListeners方法從事件注冊(cè)表(事件-監(jiān)聽器關(guān)系保存)中獲取事件監(jiān)聽器,并且通過invokeListener方法執(zhí)行監(jiān)聽器的具體邏輯;
  3. ApplicationListener就是Spring的事件監(jiān)聽器接口,所有的監(jiān)聽器都實(shí)現(xiàn)該接口,本圖中列出了典型的幾個(gè)子類其中RestartApplicationListnenerSpringBoot的啟動(dòng)框架中就有使用;
  4. 在Spring中通常是ApplicationContext本身擔(dān)任監(jiān)聽器注冊(cè)表的角色,在其子類AbstractApplicationContext中就聚合了事件廣播器ApplicationEventMulticaster和事件監(jiān)聽器ApplicationListnener,并且提供注冊(cè)監(jiān)聽器的addApplicationListnener方法;

通過上圖就能較清晰的知道當(dāng)一個(gè)事件源產(chǎn)生事件時(shí),它通過事件發(fā)布器ApplicationEventPublisher發(fā)布事件,然后事件廣播器ApplicationEventMulticaster會(huì)去事件注冊(cè)表ApplicationContext中找到事件監(jiān)聽器ApplicationListnener,并且逐個(gè)執(zhí)行監(jiān)聽器的onApplicationEvent方法,從而完成事件監(jiān)聽器的邏輯。

來到ApplicationEventPublisher 的 publishEvent 方法內(nèi)部

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {if (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);}else {getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}
}

多播事件multicastEvent方法

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));// 注意Executor executor = getTaskExecutor();// 遍歷所有的監(jiān)聽者for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {if (executor != null) {// 異步調(diào)用監(jiān)聽器executor.execute(() -> invokeListener(listener, event));}else {// 同步調(diào)用監(jiān)聽器invokeListener(listener, event);}}
}

在準(zhǔn)備執(zhí)行監(jiān)聽者方法時(shí),會(huì)先獲取容器中是否有默認(rèn)的異步線程池,如果在容器啟動(dòng)時(shí),聲明了一個(gè)異步線程池,getTaskExecutor方法一定不為null,然后異步調(diào)用執(zhí)行l(wèi)istener的業(yè)務(wù)方法,否則會(huì)同步調(diào)用執(zhí)行l(wèi)istener。

此時(shí)如果你使用注解@TransactionalEventListener監(jiān)聽,注解會(huì)失效。

具體請(qǐng)看:https://cuizb.top/myblog/article/detail/1684739163,

invokeListener方法

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {ErrorHandler errorHandler = getErrorHandler();if (errorHandler != null) {try {doInvokeListener(listener, event);}catch (Throwable err) {errorHandler.handleError(err);}}else {doInvokeListener(listener, event);}
}

doInvokeListener方法

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {// 這里是事件發(fā)生的地方listener.onApplicationEvent(event);}catch (ClassCastException ex) {......}
}

點(diǎn)擊ApplicationListener 接口 onApplicationEvent 方法的實(shí)現(xiàn),可以看到我們重寫的方法。

Spring事件ApplicationEvent源碼淺讀 - Java技術(shù)債務(wù)

總結(jié)

Spring 使用反射機(jī)制,獲取了所有繼承 ApplicationListener 接口的監(jiān)聽器,在 Spring 初始化時(shí),會(huì)把監(jiān)聽器都自動(dòng)注冊(cè)到注冊(cè)表中。

Spring 的事件發(fā)布非常簡單,我們來總結(jié)一下:

  1. 定義一個(gè)繼承ApplicationEvent的事件;
  2. 定義一個(gè)實(shí)現(xiàn)ApplicationListener的監(jiān)聽器或者使用@EventListener監(jiān)聽事件;
  3. 定義一個(gè)發(fā)送者,調(diào)用ApplicationContext直接發(fā)布或者使用ApplicationEventPublisher來發(fā)布自定義事件;

最后,發(fā)布-訂閱模式可以很好的將業(yè)務(wù)邏輯進(jìn)行解耦,大大提高了可維護(hù)性、可擴(kuò)展性。

Spring事件ApplicationEvent源碼淺讀 - Java技術(shù)債務(wù)


--------------------------------------------------------------歡迎叨擾此地址---------------------------------------------------------------

本文作者:Java技術(shù)債務(wù)
原文鏈接:https://cuizb.top/myblog/article/detail/1697189495
版權(quán)聲明: 本博客所有文章除特別聲明外,均采用 CC BY 3.0 CN協(xié)議進(jìn)行許可。轉(zhuǎn)載請(qǐng)署名作者且注明文章出處。

http://www.risenshineclean.com/news/6407.html

相關(guān)文章:

  • 網(wǎng)站開發(fā)合同范本下載google網(wǎng)頁版登錄入口
  • 企業(yè)建站公司電話百度關(guān)鍵詞快排
  • 用ps做網(wǎng)站頁面seo查詢 站長工具
  • 大型網(wǎng)絡(luò)游戲排行榜2021前十名湖南專業(yè)關(guān)鍵詞優(yōu)化服務(wù)水平
  • 網(wǎng)站ui設(shè)計(jì)包括哪些原則谷歌seo 外貿(mào)建站
  • 怎么自建導(dǎo)購網(wǎng)站做淘客公司seo排名優(yōu)化
  • 網(wǎng)站開發(fā)語言 微信接口百度快照優(yōu)化培訓(xùn)班
  • 河北省建設(shè)執(zhí)業(yè)資格中心網(wǎng)站網(wǎng)絡(luò)營銷推廣技巧
  • 西充縣住房和城鄉(xiāng)規(guī)劃建設(shè)局網(wǎng)站google網(wǎng)站增加關(guān)鍵詞
  • 哪些網(wǎng)站是做b2b的網(wǎng)站維護(hù)一年一般多少錢?
  • 網(wǎng)站建設(shè)容易嗎seo自媒體培訓(xùn)
  • 連云港做網(wǎng)站最好惠州網(wǎng)站制作推廣
  • 專做海島游的網(wǎng)站如何交換友情鏈接
  • 網(wǎng)站建設(shè)設(shè)計(jì)解決方案網(wǎng)推拉新app推廣接單平臺(tái)
  • 電腦版qq在線登錄網(wǎng)頁入口百度地圖關(guān)鍵詞排名優(yōu)化
  • 南昌自助建站模板今天上海最新新聞事件
  • 網(wǎng)站 建設(shè) 成品小程序開發(fā)平臺(tái)官網(wǎng)
  • hbuilder做網(wǎng)站頁面背景色鄭州seo公司哪家好
  • 58同城煙臺(tái)網(wǎng)站建設(shè)肇慶網(wǎng)站推廣排名
  • 建英語網(wǎng)站第一推廣網(wǎng)
  • 有沒有什么 網(wǎng)站能夠做試卷排名優(yōu)化服務(wù)
  • 做網(wǎng)站被坑溫州云優(yōu)化seo
  • 淘寶客網(wǎng)站做百度推廣登錄百度賬號(hào)注冊(cè)
  • 網(wǎng)站建設(shè)實(shí)習(xí)生怎么樣百度一下打開網(wǎng)頁
  • 福安建設(shè)網(wǎng)站網(wǎng)絡(luò)營銷公司好不好
  • 網(wǎng)站建設(shè)空間選擇的重要性廈門seo管理
  • 進(jìn)行seo網(wǎng)站建設(shè)今日最新的新聞
  • 哪個(gè)網(wǎng)站可以做計(jì)算機(jī)二級(jí)的題關(guān)鍵詞優(yōu)化系統(tǒng)
  • 微信紅包封面分銷平臺(tái)搜索引擎優(yōu)化的內(nèi)部優(yōu)化
  • 南陽做網(wǎng)站seo的收錄網(wǎng)站的平臺(tái)有哪些