Spring事件機制問題如何排查

這篇文章給大家分享的是有關(guān)Spring事件機制問題如何排查的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考。一起跟隨小編過來看看吧。

成都創(chuàng)新互聯(lián)是一家專注網(wǎng)站建設(shè)、網(wǎng)絡(luò)營銷策劃、重慶小程序開發(fā)、電子商務(wù)建設(shè)、網(wǎng)絡(luò)推廣、移動互聯(lián)開發(fā)、研究、服務(wù)為一體的技術(shù)型公司。公司成立十年以來,已經(jīng)為上1000+成都房屋鑒定各業(yè)的企業(yè)公司提供互聯(lián)網(wǎng)服務(wù)?,F(xiàn)在,服務(wù)的上1000+客戶與我們一路同行,見證我們的成長;未來,我們一起分享成功的喜悅。

前言:之前使用Spring的事件機制來改造系統(tǒng),完成了部分模塊的解耦。但是實際使用時卻發(fā)現(xiàn)存在以下問題:

當(dāng)ApplicationEventPublisher批量推送ApplicationEvent時,如果ApplicationListener在處理的過程中拋出異常,則會導(dǎo)致后續(xù)的推送中斷。

PS:Spring版本為5.1.5.RELEASE

下面將會展示一個復(fù)盤的示例

復(fù)盤示例

自定義事件

import org.springframework.context.ApplicationEvent;

/**
 * 自定義事件
 * @author RJH
 * create at 2018/10/29
 */
public class SimpleEvent extends ApplicationEvent {

    private int i;
    /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public SimpleEvent(Object source) {
        super(source);
        i=Integer.valueOf(source.toString());
    }

    public int getI() {
        return i;
    }

}

事件監(jiān)聽器

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * 自定義事件監(jiān)聽器
 * @author RJH
 * create at 2018/10/29
 */
@Component
public class SimpleEventListener implements ApplicationListener<SimpleEvent> {

    @Override
    public void onApplicationEvent(SimpleEvent event) {
        if(event.getI()%10==0){
            throw new RuntimeException();
        }
        System.out.println("Time:"+event.getTimestamp()+" event:"+event.getSource());
    }

}

事件推送

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 事件推送
 * @author RJH
 * create at 2018/10/29
 */
public class EventApplication {

    public static void main(String[] args) {
        //掃描特定package
        ApplicationContext context=new AnnotationConfigApplicationContext("com.rjh.event");
        for(int i=1;i<=100;i++){//批量推送事件
            context.publishEvent(new SimpleEvent(i));
        }
    }
}

運行結(jié)果

Time:1553607971143 event:1
Time:1553607971145 event:2
Time:1553607971145 event:3
Time:1553607971145 event:4
Time:1553607971145 event:5
Time:1553607971145 event:6
Time:1553607971146 event:7
Time:1553607971146 event:8
Time:1553607971146 event:9
Exception in thread "main" java.lang.RuntimeException
    at com.rjh.event.SimpleEventListener.onApplicationEvent(SimpleEventListener.java:17)
    at com.rjh.event.SimpleEventListener.onApplicationEvent(SimpleEventListener.java:11)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
    at com.rjh.event.EventApplication.main(EventApplication.java:17)

分析

期待結(jié)果為SimpleEventListener拋出異常不影響EventApplication中后續(xù)事件的推送。但是實際上卻是SimpleEventListener拋出異常會導(dǎo)致EventApplication后續(xù)事件的推送中斷。從這里可以看出事件的推送和事件的監(jiān)聽是同步阻塞進行,而并非是異步。詳細可以參考文檔中的介紹:

Notice that ApplicationListener is generically parameterized with the type of your custom event (BlackListEvent in the preceding example). This means that the onApplicationEvent() method can remain type-safe, avoiding any need for downcasting. You can register as many event listeners as you wish, but note that, by default, event listeners receive events synchronously. This means that the publishEvent() method blocks until all listeners have finished processing the event. One advantage of this synchronous and single-threaded approach is that, when a listener receives an event, it operates inside the transaction context of the publisher if a transaction context is available. If another strategy for event publication becomes necessary, See the javadoc for Spring’s ApplicationEventMulticaster interface.

解決辦法

將事件監(jiān)聽改造為異步處理,這里將會展示基于JavaConfig即注解的解決方案

開啟異步

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

/**
 * 開啟異步服務(wù)配置類
 * @author RJH
 * create at 2019-03-26
 */
@EnableAsync
@Configuration
public class AsyncConfig {

}

異步事件監(jiān)聽

import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * 異步事件監(jiān)聽
 * @author RJH
 * create at 2019-03-26
 */
@Component
public class AsyncSimpleEventListener {

    @EventListener
    @Async
    public void handleEvent(SimpleEvent event){
        if(event.getI()%10==0){
            throw new RuntimeException();
        }
        System.out.println("Time:"+event.getTimestamp()+" event:"+event.getSource());
    }
}

運行結(jié)果

Time:1553614469990 event:1
Time:1553614470007 event:72
Time:1553614470006 event:64
Time:1553614470006 event:67
Time:1553614470007 event:73
Time:1553614470007 event:71
Time:1553614470007 event:75
Time:1553614470006 event:68
Time:1553614470007 event:69
Time:1553614470006 event:62
Time:1553614470005 event:61
Time:1553614470006 event:63
Time:1553614470006 event:65
Time:1553614470007 event:74
Time:1553614470006 event:66
Time:1553614470005 event:59
Time:1553614470005 event:57
Time:1553614470005 event:55
Time:1553614470005 event:58
Time:1553614470004 event:51
Time:1553614470004 event:52
Time:1553614470002 event:43
Time:1553614470004 event:53
Time:1553614470002 event:38
Time:1553614470001 event:36
Time:1553614470004 event:54
Time:1553614470001 event:33
Time:1553614470000 event:29
Time:1553614470000 event:27
Time:1553614470005 event:56
Time:1553614469999 event:23
Time:1553614469999 event:22
Time:1553614469999 event:21
三月 26, 2019 11:34:30 下午 org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler handleUncaughtException
嚴重: Unexpected error occurred invoking async method: public void com.rjh.event.AsyncSimpleEventListener.handleEvent(com.rjh.event.SimpleEvent)
Time:1553614470000 event:24java.lang.RuntimeException
    at com.rjh.event.AsyncSimpleEventListener.handleEvent(AsyncSimpleEventListener.java:19)

    at com.rjh.event.AsyncSimpleEventListener$$FastClassBySpringCGLIB$$61742dbf.invoke(<generated>)
Time:1553614469998 event:15    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:736)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)

    at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
...內(nèi)容過長省略部分結(jié)果

分析:改造為異步執(zhí)行后,事件監(jiān)聽就由線程池進行處理,此處還可以通過自定義線程池,并設(shè)置異常處理器來處理未捕獲的異常。

感謝各位的閱讀!關(guān)于Spring事件機制問題如何排查就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

網(wǎng)站欄目:Spring事件機制問題如何排查
新聞來源:http://bm7419.com/article28/jdjcjp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計Google、品牌網(wǎng)站制作、網(wǎng)站改版、標簽優(yōu)化、App設(shè)計

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管