<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring 與 Spring Boot 中的事件機(jī)制

          共 6673字,需瀏覽 14分鐘

           ·

          2020-08-09 02:20

          點(diǎn)擊上方藍(lán)色“程序猿DD”,選擇“設(shè)為星標(biāo)”

          回復(fù)“資源”獲取獨(dú)家整理的學(xué)習(xí)資料!

          作者 | 溫安適

          來源 |?https://my.oschina.net/floor/blog/4404731

          引言

          spring事件機(jī)制,有3個(gè)核心部分,事件,監(jiān)聽方式,廣播器,下面我們分別介紹。

          Spring事件

          spring的事件的API對應(yīng)ApplicationEvent。它繼承了ava.util.EventObject。顯示調(diào)用父類構(gòu)造器傳遞事件源。

          public?abstract?class?ApplicationEvent?extends?EventObject?{
          ?????///省略其他代碼
          ??public?ApplicationEvent(Object?source)?{
          ??super(source);
          ??this.timestamp?=?System.currentTimeMillis();
          ??}
          ???????//省略其他代碼
          }

          Spring內(nèi)置事件

          事件名注釋
          ContextRefreshedEventSpring應(yīng)用上下文就緒事件
          ContextStartedEventSpring應(yīng)用上下文啟動(dòng)事件
          ContextStopedEventSpring應(yīng)用上下文停止事件
          ContextClosedEventSpring應(yīng)用上下文關(guān)閉事件

          允許泛型事件自定義,如果有興趣可以參看:org.springframework.context.PayloadApplicationEvent

          Spring事件監(jiān)聽手段

          2種監(jiān)聽手段

          \1. 實(shí)現(xiàn)ApplicationListener接口 或 @EventListener,可監(jiān)聽1到多種事件,支持泛型事件

          \2. @EventListener方法上@Async,可使用@EventListener方法異步化,但是被注解的方法的返回值應(yīng)該為void,其實(shí)返回值沒有意義。

          表@EventListener的同步與異步區(qū)別

          方法類型訪問修飾符返回類型參數(shù)數(shù)量參數(shù)類型備注
          同步public任意類型0或1監(jiān)聽事件類型或其子類會(huì)將返回值作為事件向后傳播
          異步publicvoid0或1監(jiān)聽事件類型或其子類如果出錯(cuò)不會(huì)傳播給調(diào)用者。不會(huì)向后傳播事件

          @EventListener原理

          找入口

          EventListenerMethodProcessor 就是處理@EventListener注解的入口類

          找主要方法

          查看 EventListenerMethodProcessor 的類注釋,簡要翻譯如下:

          1.將@EventListener方法轉(zhuǎn)換為**ApplicationListener示例2.實(shí)現(xiàn)BeanFactoryPostProcessor用于檢索EventListenerFactory避免AOP增強(qiáng),EventListenerFactory

          在查看, EventListenerMethodProcessor的類圖

          img

          ApplicationContextAware 用于注入ApplicationContext。

          BeanFactoryPostProcessor根據(jù)類注釋可知用于獲取EventListenerFactory。

          這里最需要關(guān)注的應(yīng)該是SmartInitializingSingleton#afterSingletonsInstantiated方法。

          查看該方法的注釋

          public?interface?SmartInitializingSingleton?{

          ???/**
          ????*?預(yù)實(shí)例化完成之后調(diào)用,保證所有常規(guī)單例Bean創(chuàng)建完畢
          ????*?調(diào)用ListableBeanFactory#getBeansOfType沒有任何副作用
          ????*?注意:?
          ????*?對于延遲加載的單例Bean,不會(huì)觸發(fā)這個(gè)回調(diào)。
          ????*?并且其他作用域的Bean,也不會(huì)觸發(fā)這個(gè)回調(diào)。
          ????*?謹(jǐn)慎使用,應(yīng)僅用于引導(dǎo)功能。
          ????*/

          ???void?afterSingletonsInstantiated();
          }

          afterSingletonsInstantiated 從方法注釋上可以看出,這個(gè)方法可以用于引導(dǎo)功能。

          查看源碼EventListenerMethodProcessor ,邏輯就是找BeanName和Bean對應(yīng)的Type,具體邏輯委托給processBean,下面是processBean的源碼

          public?class?EventListenerMethodProcessor?{
          ????//省略其他部分
          private?void?processBean(final?String?beanName,?final?Class?targetType)?{
          ???if?(!this.nonAnnotatedClasses.contains(targetType)?&&
          ?????????!targetType.getName().startsWith("java")?&&
          ?????????!isSpringContainerClass(targetType))?{

          ??????Map?annotatedMethods?=?null;
          ??????try?{
          ??????????//找出所有EventListener注解的方法
          ?????????annotatedMethods?=?MethodIntrospector.selectMethods(targetType,
          ???????????????(MethodIntrospector.MetadataLookup)?method?->
          ?????????????????????AnnotatedElementUtils.findMergedAnnotation(method,?EventListener.class));
          ??????}
          ??????catch?(Throwable?ex)?{
          ?????????//?An?unresolvable?type?in?a?method?signature,?probably?from?a?lazy?bean?-?let's?ignore?it.
          ?????????if?(logger.isDebugEnabled())?{
          ????????????logger.debug("Could?not?resolve?methods?for?bean?with?name?'"?+?beanName?+?"'",?ex);
          ?????????}
          ??????}

          ??????if?(CollectionUtils.isEmpty(annotatedMethods))?{
          ?????????this.nonAnnotatedClasses.add(targetType);
          ?????????if?(logger.isTraceEnabled())?{
          ????????????logger.trace("No?@EventListener?annotations?found?on?bean?class:?"?+?targetType.getName());
          ?????????}
          ??????}
          ??????else?{
          ?????????//?Non-empty?set?of?methods
          ?????????ConfigurableApplicationContext?context?=?this.applicationContext;
          ?????????Assert.state(context?!=?null,?"No?ApplicationContext?set");
          ?????????List?factories?=?this.eventListenerFactories;
          ?????????Assert.state(factories?!=?null,?"EventListenerFactory?List?not?initialized");
          ?????????for?(Method?method?:?annotatedMethods.keySet())?{
          ????????????for?(EventListenerFactory?factory?:?factories)?{
          ???????????????if?(factory.supportsMethod(method))?{
          ??????????????????Method?methodToUse?=?AopUtils.selectInvocableMethod(method,?context.getType(beanName));
          ?????????????????//通過EventListenerFactory轉(zhuǎn)換為ApplicationListenerMethodAdapter
          ???????????????????ApplicationListener?applicationListener?=
          ????????????????????????factory.createApplicationListener(beanName,?targetType,?methodToUse);
          ??????????????????if?(applicationListener?instanceof?ApplicationListenerMethodAdapter)?{
          ?????????????????????((ApplicationListenerMethodAdapter)?applicationListener).init(context,?this.evaluator);
          ??????????????????}
          ??????????????????//將該事件監(jiān)聽器注冊到應(yīng)用上下文中。
          ??????????????????context.addApplicationListener(applicationListener);
          ??????????????????break;
          ???????????????}
          ????????????}
          ?????????}
          ?????????if?(logger.isDebugEnabled())?{
          ????????????logger.debug(annotatedMethods.size()?+?"?@EventListener?methods?processed?on?bean?'"?+
          ??????????????????beanName?+?"':?"?+?annotatedMethods);
          ?????????}
          ??????}
          ???}
          }
          }

          AopUtils.selectInvocableMethod 是不允許訪問,私有方法,靜態(tài)方法,代理的方法,也就印證了 @EventListener必須用public修飾

          概要邏輯

          1.這個(gè)方法的邏輯就是將@EventListener的方法,

          2.通過 EventListenerFactory轉(zhuǎn)換為ApplicationListenerMethodAdapter,

          3.該事件監(jiān)聽器注冊上線文中。

          @EventListener總結(jié)

          1. EventListenerMethodProcessor 是@EventListener的生命周期處理器,實(shí)現(xiàn)了 SmartInitializingSingleton接口的afterSingletonsInstantiated 方法,進(jìn)行了:
          • 這個(gè)方法的邏輯就是將@EventListener的方法,
          • 通過EventListenerFactory轉(zhuǎn)換為ApplicationListenerMethodAdapter,
          • 該事件監(jiān)聽器注冊上線文中。
          1. DefaultEventListenerFactory是@EventListener方法與ApplicationListener的適配工廠

          2. ApplicationListenerMethodAdapter為適配類。

          Spring的廣播器

          廣播器為ApplicationEventMulticaster,它的默認(rèn)實(shí)現(xiàn)為SimpleApplicationEventMulticaster

          它主要有2個(gè)責(zé)任,維護(hù)ApplicationListener關(guān)聯(lián)關(guān)系這個(gè)比較簡單,我們關(guān)注下廣播消息。

          @Override
          public?void?multicastEvent(final?ApplicationEvent?event,?@Nullable?ResolvableType?eventType)?{
          ???ResolvableType?type?=?(eventType?!=?null???eventType?:?resolveDefaultEventType(event));
          ???Executor?executor?=?getTaskExecutor();
          ???for?(ApplicationListener?listener?:?getApplicationListeners(event,?type))?{
          ??????if?(executor?!=?null)?{
          ?????????executor.execute(()?->?invokeListener(listener,?event));
          ??????}
          ??????else?{
          ?????????invokeListener(listener,?event);
          ??????}
          ???}
          }

          調(diào)用getApplicationListeners,遍歷調(diào)用onApplicationEvent(ApplicationEvent)。

          查看getApplicationListeners方法在其父類 AbstractApplicationEventMulticaster中。

          protected?Collection>?getApplicationListeners(
          ??????ApplicationEvent?event,?ResolvableType?eventType)?{

          ???Object?source?=?event.getSource();
          ???Class?sourceType?=?(source?!=?null???source.getClass()?:?null);
          ???ListenerCacheKey?cacheKey?=?new?ListenerCacheKey(eventType,?sourceType);

          ???//?Quick?check?for?existing?entry?on?ConcurrentHashMap...
          ???ListenerRetriever?retriever?=?this.retrieverCache.get(cacheKey);
          ???if?(retriever?!=?null)?{
          ??????return?retriever.getApplicationListeners();
          ???}

          ???if?(this.beanClassLoader?==?null?||
          ?????????(ClassUtils.isCacheSafe(event.getClass(),?this.beanClassLoader)?&&
          ???????????????(sourceType?==?null?||?ClassUtils.isCacheSafe(sourceType,?this.beanClassLoader))))?{
          ??????//?Fully?synchronized?building?and?caching?of?a?ListenerRetriever
          ??????synchronized?(this.retrievalMutex)?{
          ?????????retriever?=?this.retrieverCache.get(cacheKey);
          ?????????if?(retriever?!=?null)?{
          ????????????return?retriever.getApplicationListeners();
          ?????????}
          ?????????retriever?=?new?ListenerRetriever(true);
          ?????????Collection>?listeners?=
          ???????????????retrieveApplicationListeners(eventType,?sourceType,?retriever);
          ?????????this.retrieverCache.put(cacheKey,?retriever);
          ?????????return?listeners;
          ??????}
          ???}
          ???else?{
          ??????//?No?ListenerRetriever?caching?->?no?synchronization?necessary
          ??????return?retrieveApplicationListeners(eventType,?sourceType,?null);
          ???}
          }

          內(nèi)部維護(hù)一個(gè)final Map retrieverCache 維護(hù)事件類型與數(shù)據(jù)源的類型

          ListenerCacheKey為eventType(對應(yīng)泛型或者事件類本身) 和sourceType(ApplicationEvent構(gòu)造器中的source),(對應(yīng)ApplicationEvent)。

          SimpleApplicationEventMulticaster總結(jié):

          1. SimpleApplicationEventMulticaster承擔(dān)2個(gè)職責(zé),關(guān)聯(lián)ApplicationListener,廣播ApplicationEvent。

          2. SimpleApplicationEventMulticaster 內(nèi)部維護(hù)一個(gè)final Map retrieverCache 維護(hù)事件類型與數(shù)據(jù)源的類型

          3. ListenerCacheKey為eventType(對應(yīng)泛型或者事件類本身) 和sourceType(ApplicationEvent構(gòu)造器中的source)

          4. ListenerRetriever是AbstractApplicationEventMulticaster的內(nèi)部類,對應(yīng)ApplicationListener集合

          5. ApplicationEventMulticaster廣播事件,multicastEvent(ApplicationEvent)和multicastEvent(ApplicationEvent,ResolvableType)

          內(nèi)部調(diào)用getApplicationListeners,遍歷調(diào)用onApplicationEvent(ApplicationEvent)

          補(bǔ)充說明:

          通過ApplicationEventPublisherAware獲得的ApplicationEventPublisher,是什么?

          解決這個(gè),就需要查看ApplicationContextAwareProcessor#postProcessBeforeInitialization

          內(nèi)部調(diào)用了 invokeAwareInterfaces方法,處理各種Aware接口的注入邏輯。

          private?void?invokeAwareInterfaces(Object?bean)?{
          ???if?(bean?instanceof?EnvironmentAware)?{
          ??????((EnvironmentAware)?bean).setEnvironment(this.applicationContext.getEnvironment());
          ???}
          ???if?(bean?instanceof?EmbeddedValueResolverAware)?{
          ??????((EmbeddedValueResolverAware)?bean).setEmbeddedValueResolver(this.embeddedValueResolver);
          ???}
          ???if?(bean?instanceof?ResourceLoaderAware)?{
          ??????((ResourceLoaderAware)?bean).setResourceLoader(this.applicationContext);
          ???}
          ???if?(bean?instanceof?ApplicationEventPublisherAware)?{
          ??????((ApplicationEventPublisherAware)?bean).setApplicationEventPublisher(this.applicationContext);
          ???}
          ???if?(bean?instanceof?MessageSourceAware)?{
          ??????((MessageSourceAware)?bean).setMessageSource(this.applicationContext);
          ???}
          ???if?(bean?instanceof?ApplicationContextAware)?{
          ??????((ApplicationContextAware)?bean).setApplicationContext(this.applicationContext);
          ???}
          }

          看到這里,答案就有了。ApplicationEventPublisherAware所獲得的ApplicationEventPublisher實(shí)例就是當(dāng)前的ApplicationContext。

          簡述Spring Boot事件

          Springboot事件

          SpringBoot事件繼承ApplicationEvent,也是SpringApplicationEvent的子類

          SpringBoot事件源是SpringApplication,內(nèi)部事件根據(jù)EventPublishingRunListener的生命周期回調(diào)方法依次發(fā)布。

          • ApplicationStartingEvent 1.5出現(xiàn)
          • ApplicationEnvironmentPreparedEvent
          • ApplicationPreparedEvent
          • ApplicationStartedEvent
          • ApplicationReadyEvent, spring應(yīng)用上下文之后發(fā)布
          • ApplicationFailedEvent, spring應(yīng)用上下文之后發(fā)布

          Spring Boot事件監(jiān)聽手段

          SpringApplication關(guān)聯(lián)的SpringApplication關(guān)聯(lián)ApplicationListener

          1. class-path下,META-INF/spring.factories資源中的ApplicationListener對象集合

          2. SpringApplication#addListeners(...)或SpringApplicationBuilder#listeners(...)顯示裝配

          Spring Boot的廣播器

          SimpleApplicationEventMulticaster,是特定的,2.0以后不與spring framework共用。


          往期推薦

          為什么阿里規(guī)定事務(wù)注解@Transactional中指定rollbackFor?

          面試:說說參數(shù)驗(yàn)證 @Validated 和 @Valid 的區(qū)別?

          SQL查找是否"存在",別再count了!

          IntelliJ IDEA 2020.2 發(fā)布:支持Java 15、GitHub審查...

          Mybatis 框架下 SQL 注入攻擊的 3 種方式,真是防不勝防!


          歡迎加入我的知識星球,聊技術(shù)、說職場、侃社會(huì)。



          星球兩大分享內(nèi)容

          瀏覽 35
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  丁香五月婷婷综合小说 | 狠狠操亚洲 | 日韩动态视频 | 影音先锋男人的资源网站 | 免费播放一区二区三区四区 |