国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

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

移動(dòng)網(wǎng)站如何做權(quán)重鎮(zhèn)江網(wǎng)站制作公司

移動(dòng)網(wǎng)站如何做權(quán)重,鎮(zhèn)江網(wǎng)站制作公司,h5手機(jī)制作網(wǎng)站開發(fā),重慶網(wǎng)站建設(shè)開發(fā)Spring事件監(jiān)聽機(jī)制是Spring框架中的一種重要技術(shù),允許組件之間進(jìn)行松耦合通信。通過使用事件監(jiān)聽機(jī)制,應(yīng)用程序的各個(gè)組件可以在其他組件不直接引用的情況下,相互發(fā)送和接受消息。 需求 在技術(shù)派中有這樣一個(gè)需求,當(dāng)發(fā)布文章或…

Spring事件監(jiān)聽機(jī)制是Spring框架中的一種重要技術(shù),允許組件之間進(jìn)行松耦合通信。通過使用事件監(jiān)聽機(jī)制,應(yīng)用程序的各個(gè)組件可以在其他組件不直接引用的情況下,相互發(fā)送和接受消息。

需求

在技術(shù)派中有這樣一個(gè)需求,當(dāng)發(fā)布文章或者文章下線時(shí),會(huì)發(fā)布一個(gè)事件給SiteMap(站點(diǎn)地圖,幫助搜索引擎有效的抓取和索引網(wǎng)站),SiteMap監(jiān)聽到該事件后會(huì)進(jìn)行更新。

事件監(jiān)聽的本質(zhì)是觀察者模式的應(yīng)用包括事件、事件監(jiān)聽器、事件發(fā)布器等主要組件。

事件:一個(gè)實(shí)現(xiàn)了ApplicationEvent類的對(duì)象,代表了應(yīng)用程序中某個(gè)特定的事件。我們可以根據(jù)需要?jiǎng)?chuàng)建自定義事件,只要繼承ApplicationEvent類并添相關(guān)的屬性和方法就可以了。

事件監(jiān)聽器:實(shí)現(xiàn)了ApplicationListener<E>接口的對(duì)象,其中E表示事件監(jiān)聽器需要處理的事件類型。監(jiān)聽器可以通過onApplicationEvent(E event)方法處理接受到的事件,另外也可以使用@EventListener注解來簡(jiǎn)化事件監(jiān)聽器的實(shí)現(xiàn),技術(shù)派正是采用的這種方式。

事件發(fā)布器:事件發(fā)布器負(fù)責(zé)將事件發(fā)布給所有關(guān)注該事件的監(jiān)聽器,在Spring中,ApplicationEventPublisher接口定義了事件發(fā)布的基本功能,而ApplicationEventPublisherAware接口允許組件獲取到事件發(fā)布器的引用。Spring的核心容器ApplicationContext實(shí)現(xiàn)了ApplicationEventPublisher接口,因此在Spring應(yīng)用中,通常直接使用ApplicationContext作為事件發(fā)布器,技術(shù)派采用該方式。

實(shí)例

第一步(事件)

創(chuàng)建自定義事件ArticleMsgEvent,繼承ApplicationEvent。

@Getter
@Setter
@ToString
@EqualsAndHashCode(callSuper = true)
public class ArticleMsgEvent<T> extends ApplicationEvent {private ArticleEventEnum type;private T content;public ArticleMsgEvent(Object source, ArticleEventEnum type, T content) {super(source);this.type = type;this.content = content;}
}

類上的四個(gè)注解為lombok提供。兩個(gè)字段,

type:枚舉類型(ArticleEventEnum),代表事件的類型。

表示文章上線或者下線。

content:泛型(T),表示事件的內(nèi)容,在本例中,我們會(huì)傳一個(gè)文章的ID。

source:在構(gòu)造方法里賣我們還會(huì)傳一個(gè)Object類型的數(shù)據(jù),表示事件的來源,也就是事件的發(fā)布者。

ApplicationEvent:是Spring Framework框架中用于定義事件的基類。

第二步(發(fā)布事件)

定義SpringUtil工具類,實(shí)現(xiàn)了ApplicationContexAware

@Component
public class SpringUtil implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringUtil.context = applicationContext;}/*** 發(fā)布事件消息** @param event*/public static void publishEvent(ApplicationEvent event) {context.publishEvent(event);}

通過實(shí)現(xiàn)ApplicationContextAware接口,可以讓這個(gè)類在Spring容器啟動(dòng)時(shí)自動(dòng)獲得ApplicationContext引用。(作為事件發(fā)布器)@Component可以讓該類被Spring容器自動(dòng)實(shí)例化和管理。

自動(dòng)裝配過程是通過Spring得ApplicationContextAwareProcessor類實(shí)現(xiàn)得,它是一個(gè)后置處理器。在Spring容器初始化時(shí),他會(huì)檢查所有得Bean,如果Bean實(shí)現(xiàn)了ApplicationContextAware接口。他會(huì)調(diào)用setApplicationContext方法將ApplicationContext的引用傳遞給Bean。

第三步(用事件)

通過調(diào)用SpringUtil.publishEvent()發(fā)布事件。在ArticleSettingServiceImpl類中。

@Override
public void updateArticle(ArticlePostReq req) {
ArticleDO article = articleDao.getById(req.getArticleId());
if (article == null) {return;
}if (StringUtils.isNotBlank(req.getTitle())) {article.setTitle(req.getTitle());
}
article.setShortTitle(req.getShortTitle());ArticleEventEnum operateEvent = null;
if (req.getStatus() != null) {article.setStatus(req.getStatus());if (req.getStatus() == PushStatusEnum.OFFLINE.getCode()) {operateEvent = ArticleEventEnum.OFFLINE;} else if (req.getStatus() == PushStatusEnum.REVIEW.getCode()) {operateEvent = ArticleEventEnum.REVIEW;} else if (req.getStatus() == PushStatusEnum.ONLINE.getCode()) {operateEvent = ArticleEventEnum.ONLINE;}//            switch (req.getStatus()){//                case 0 ://                    operateEvent = ArticleEventEnum.OFFLINE;//                    break;//                case 3 ://                    operateEvent = ArticleEventEnum.REVIEW;//                    break;//                case 2 ://                    operateEvent = ArticleEventEnum.ONLINE;//                    break;//                default://                    break;//            }}
articleDao.updateById(article);if (operateEvent != null) {// 發(fā)布文章待審核、上線、下線事件SpringUtil.publishEvent(new ArticleMsgEvent<>(this, operateEvent, article.getId()));
}
}

第四步(監(jiān)聽并處理事件)

通過 @EventListener注解來處理事件,在SitemapServiceImpl類中可以看到。

/*** 基于文章的上下線,自動(dòng)更新站點(diǎn)地圖** @param event*/
@EventListener(ArticleMsgEvent.class)
public void autoUpdateSiteMap(ArticleMsgEvent<Long> event) {ArticleEventEnum type = event.getType();if (type == ArticleEventEnum.ONLINE) {addArticle(event.getContent());} else if (type == ArticleEventEnum.OFFLINE || type == ArticleEventEnum.DELETE) {rmArticle(event.getContent());}
}public void addArticle(Long articleId) {
RedisClient.hSet(SITE_MAP_CACHE_KEY, String.valueOf(articleId), System.currentTimeMillis());
}public void rmArticle(Long articleId) {RedisClient.hDel(SITE_MAP_CACHE_KEY, String.valueOf(articleId));
}

當(dāng)ArticleMsgEvent類型的事件被發(fā)布時(shí),此方法自動(dòng)被觸發(fā),在該方法中,首先獲得事件的類型(ArticleEventEnum枚舉值),然后根據(jù)事件類型執(zhí)行相應(yīng)的操作,上線時(shí)將文章添加到SiteMap,下線時(shí)從SiteMap中刪除。

測(cè)試

這個(gè)就時(shí)技術(shù)派中的事件監(jiān)聽機(jī)制了。

啟動(dòng)Redis,啟動(dòng)服務(wù)端,啟動(dòng)admin端,在后端找一篇文章下線文章。

就可以在debug模式下看到事件觸發(fā)了。

原理分析

Spring事件監(jiān)聽機(jī)制涉及到s四個(gè)主要的類:

事件對(duì)象:ApplicationEvent

事件監(jiān)聽器:ApplicationLisener,事件監(jiān)聽器,可以通過@EventListener注解定義事件處理方法,而無需實(shí)現(xiàn)ApplicationListener接口

事件發(fā)布者:ApplicationEventPublisher,在Spring中可以通過ApplicationEventPublisherAware接口或使用@Autowired注解來注入ApplicationEventPublisher實(shí)例,當(dāng)事件被發(fā)布時(shí),Spring會(huì)自動(dòng)調(diào)用已注冊(cè)的ApplicationListener實(shí)現(xiàn)類得onApplicationEvent()方法。

事件管理者:ApplicationEventMulticaster,管理監(jiān)聽器和發(fā)布事件,通常由SimpleApplicationEventMulticaster類實(shí)現(xiàn)。他會(huì)遍歷所有已經(jīng)注冊(cè)的監(jiān)聽器,并調(diào)用他們的onApplicationEvent()方法。

ApplicationEvent

ApplicationEvent繼承了EventObject對(duì)象。

來看看ApplicationEvent的子類關(guān)系圖

ApplicationEvent 有一個(gè)重要的子類 ApplicationContextEvent,而ApplicationContextEvent 又有 4 個(gè)重要的子類:

ContextStartedEvent:當(dāng) Spring 容器啟動(dòng)時(shí)觸發(fā)該事件。這意味著所有 Bean 都已加載,并且 ApplicationContext 已初始化。

ContextStoppedEvent:當(dāng) Spring 容器停止時(shí)觸發(fā)該事件。當(dāng)容器關(guān)閉并停止處理請(qǐng)求時(shí),通常會(huì)觸發(fā)此事件。

ContextRefreshedEvent:當(dāng) ApplicationContext 刷新時(shí)觸發(fā)該事件。這表示所有Bean 都已創(chuàng)建,并且已初始化所有單例 Bean(前提是它們?cè)谌萜鞒跏蓟瘯r(shí)需要初始化)

ContextClosedEvent:當(dāng) Spring 容器關(guān)閉時(shí)觸發(fā)該事件。這表示所有 Bean 都已銷塾Spring 容器已清理資源并停止,

ApplicationListener

ApplicationListener繼承EventListener接口,并要求實(shí)現(xiàn)onApplicationEvent(E event)方法。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E event);
}

onApplicationEvent(E event)方法:當(dāng)發(fā)布某個(gè)事件時(shí),所有注冊(cè)的ApplicationListener 實(shí)例的 onApplicationEvent 方法都會(huì)被調(diào)用。在這個(gè)方法中,可以編寫處理特定事件的邏輯。此方法接收一個(gè)類型為E的參數(shù),這是 ApplicationEvent 的子類表示觸發(fā)的事件。

當(dāng) Spring 應(yīng)用啟動(dòng)時(shí),Spring 會(huì)掃描所有的 Bean,尋找使用了 @EventListener 注解的方法。一旦找到這樣的方法,Spring 會(huì)為這些方法創(chuàng)建 ApplicationListener 實(shí)例并將其注冊(cè)到 ApplicationEventMulticaster。

ApplicationEventMulticaster

ApplicationEventMulticaster 是一個(gè)接口,負(fù)責(zé)管理監(jiān)聽器和發(fā)布事件,包含了注冊(cè)監(jiān)聽器、移除監(jiān)聽器以及發(fā)布事件的方法。

Spring 容器中通常會(huì)有一個(gè)默認(rèn)的實(shí)現(xiàn),如 SimpleApplicationEventMulticaster,繼承了AbstractApplicationEventMulticaster.

AbstractApplicationEventMulticaster 主要實(shí)現(xiàn)了管理監(jiān)聽器的方法(上面接口的前 5 個(gè)方法),比如說 addApplicationListener。

public void addApplicationListener(ApplicationListener<?> listener) {Assert.notNull(listener, "ApplicationListener must not be null");if (this.applicationEventMulticaster != null) {this.applicationEventMulticaster.addApplicationListener(listener);}this.applicationListeners.add(listener);
}

最核心的一句代碼: this.defaultRetriever.applicationListeners.add(listener);,其內(nèi)部類 DefaultListenerRetriever 里面有兩個(gè)集合,用來記錄維護(hù)事件監(jiān)聽器

這就和設(shè)計(jì)模式中的發(fā)布訂閱模式一樣了,維護(hù)一個(gè) List,用來管理所有的訂閱者,當(dāng)發(fā)布者發(fā)布消息時(shí),遍歷對(duì)應(yīng)的訂閱者列表,執(zhí)行各自的回調(diào) handler。

再來看 SimpleApplicationEventMulticaster 類實(shí)現(xiàn)的廣播事件邏輯

multicastEvent 的主要作用是將給定的 ApplicationEvent 廣播給所有匹配的監(jiān)聽器

首先,通過檢査 eventType 參數(shù)是否為 nul 來確定事件類型。如果 eventType 為null,則使用 resolveDefaultEventType(event)方法從事件對(duì)象本身解析事件類型

獲取 Executor,它是一個(gè)可選的任務(wù)執(zhí)行器,用于在異步執(zhí)行監(jiān)聽器時(shí)調(diào)用。如果沒有配置 Executor,則默認(rèn)為 nul,表示使用同步執(zhí)行。

使用 getApplicationListeners(event,type)方法獲取所有匹配給定事件類型的監(jiān)聽器。

對(duì)于每個(gè)匹配的監(jiān)聽器,檢查是否有 Executor 配置。如果存在 Executor,則使用executor.execute()方法將監(jiān)聽器的調(diào)用封裝到一個(gè)異步任務(wù)中。如果沒有配置Executor,則直接同步調(diào)用監(jiān)聽器。

使用 invokeListener(listener,event)方法調(diào)用監(jiān)聽器的 onApplicationEvent方法,將事件傳遞給監(jiān)聽器。

通過這個(gè)實(shí)現(xiàn),SimpleApplicationEventMulticaster 可以將事件廣播給所有關(guān)心該事件的監(jiān)聽器,同時(shí)支持同步和異步執(zhí)行模式。

最后調(diào)用 istener.onApplicationEvent(event);也就是我們通過實(shí)現(xiàn)接口ApplicationListener 的方式來實(shí)現(xiàn)監(jiān)聽器的 onApplicationEvent 實(shí)現(xiàn)邏輯。

ApplicationEventPublisher

ApplicationEventPublisher 是一個(gè)接口,用于將事件發(fā)布給所有感興趣的監(jiān)聽器。

這個(gè)接口的實(shí)現(xiàn)類通常會(huì)將事件委托給

ApplicationEventMulticaster。在 Spring 中ApplicationContext 通常充當(dāng)事件發(fā)布者,它就實(shí)現(xiàn)了 ApplicationEventPublisher 接口。

ApplicationContext 的 publishEvent 方法的邏輯實(shí)現(xiàn)主要在類AbstractApplicationContext 中:

這段代碼的主要邏輯在這:

這段代碼的主要作用是在 ApplicationContext 初始化時(shí)處理應(yīng)用程序事件的發(fā)布。當(dāng)ApplicationContext 還沒有完全初始化時(shí),例如在refresh()方法中earlyApplicationEvents 列表會(huì)被用來保存早期的事件。在這個(gè)階段ApplicationEventMulticaster 還沒有完全配置好,因此無法直接發(fā)布事件。這些早期的事件將在 ApplicationContext 初始化完成后,ApplicationEventMulticaster 配置好后,通過 finishRefresh()方法中的 publishEvent(new ContextRefreshedEvent(this));發(fā)布。

當(dāng) ApplicationContext 初始化完成后,earlyApplicationEvents 列表將被設(shè)置為 null。此時(shí),事件可以直接通過 getApplicationEventMulticaster().multicastEvent(applicationEvent,eventType)方法發(fā)布給所有匹配的監(jiān)聽器,

這個(gè)機(jī)制確保了在 ApplicationContext 初始化過程中產(chǎn)生的事件不會(huì)丟失,而是在ApplicationContext 初始化完成后被正確地發(fā)布給所有感興趣的監(jiān)聽器。

總結(jié)

這篇內(nèi)容通過源碼的形式講解了 Spring 事件監(jiān)聽機(jī)制及其原理。

http://aloenet.com.cn/news/30046.html

相關(guān)文章:

  • 青島建設(shè)委員會(huì)網(wǎng)站網(wǎng)站關(guān)鍵詞優(yōu)化培訓(xùn)
  • wordpress幻燈片怎么建運(yùn)營(yíng)seo是什么意思
  • 不正規(guī)網(wǎng)站制作seo博客模板
  • 網(wǎng)頁設(shè)計(jì)網(wǎng)站鏈接怎么做公司網(wǎng)站推廣
  • 浦東網(wǎng)站建設(shè)公司網(wǎng)絡(luò)營(yíng)銷網(wǎng)站
  • 有什么免費(fèi)ppt模板網(wǎng)站好用的搜索引擎有哪些
  • dw怎樣去除網(wǎng)站做的頁面模板網(wǎng)站運(yùn)營(yíng)及推廣方案
  • 淘寶網(wǎng)站建設(shè)基本流程圖萬網(wǎng)域名查詢接口
  • 手機(jī)網(wǎng)站制作與建設(shè)百度收錄網(wǎng)址提交
  • 今日軍事新聞聯(lián)播在線播放長(zhǎng)沙百度快照優(yōu)化排名
  • 優(yōu)質(zhì)網(wǎng)站建設(shè)報(bào)價(jià)長(zhǎng)沙seo網(wǎng)站優(yōu)化
  • 國(guó)外扁平化網(wǎng)站企業(yè)培訓(xùn)計(jì)劃方案
  • 建設(shè)類似衣聯(lián)網(wǎng)的網(wǎng)站整合營(yíng)銷名詞解釋
  • php做的網(wǎng)站怎么上傳網(wǎng)站推廣優(yōu)化
  • h5網(wǎng)站制作費(fèi)用關(guān)鍵字c語言
  • 模擬網(wǎng)站建設(shè)平臺(tái)推廣是做什么的
  • 可以自己做效果圖的網(wǎng)站小程序自助搭建平臺(tái)
  • 學(xué)生做網(wǎng)站期末作業(yè)新產(chǎn)品推廣方案怎么寫
  • 做空氣開關(guān)那個(gè)網(wǎng)站推廣比較好百度廣告聯(lián)盟app
  • 天津企業(yè)網(wǎng)站模板建站哪家好搜索自媒體平臺(tái)
  • 網(wǎng)站建設(shè)后的效果評(píng)估sem是什么意思啊
  • wordpress插件 地圖北京做網(wǎng)絡(luò)優(yōu)化的公司
  • 做網(wǎng)站推廣多少錢百度銷售系統(tǒng)
  • 柳州市黨風(fēng)廉政建設(shè)網(wǎng)站專注網(wǎng)站建設(shè)服務(wù)機(jī)構(gòu)
  • 青海報(bào)社網(wǎng)站建設(shè)公司百度在線問答
  • 做的網(wǎng)站怎么放視頻如何做網(wǎng)站的教程
  • 網(wǎng)站建設(shè)一點(diǎn)通口碑營(yíng)銷是什么
  • 企業(yè)移動(dòng)網(wǎng)站建設(shè)商百度賬號(hào)登陸
  • 小程序設(shè)計(jì)開發(fā)國(guó)內(nèi)seo公司排名
  • 免費(fèi)做電腦網(wǎng)站網(wǎng)站視頻