本篇文章给人人带来的内容是关于Spring事宜机制题目排查的要领引见,有肯定的参考价值,有须要的朋侪能够参考一下,愿望对你有所协助。
媒介:之前运用Spring的事宜机制来革新体系,完成了部份模块的解耦。然则实际运用时却发明存在以下题目:
当ApplicationEventPublisher批量推送ApplicationEvent时,假如ApplicationListener在处置惩罚的过程当中抛出非常,则会致使后续的推送中断。
PS:Spring版本为5.1.5.RELEASE
下面将会展现一个复盘的示例
复盘示例
自定义事宜
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; } }
事宜监听器
import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * 自定义事宜监听器 * @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)); } } }
运转效果
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)
剖析
期待效果为SimpleEventListener抛出非常不影响EventApplication中后续事宜的推送。然则实际上倒是SimpleEventListener抛出非常会致使EventApplication后续事宜的推送中断。从这里能够看出事宜的推送和事宜的监听是同步壅塞举行,而并非是异步。细致能够参考文档中的引见:
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.
解决办法
将事宜监听革新为异步处置惩罚,这里将会展现基于JavaConfig即注解的解决方案
开启异步
import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; /** * 开启异步效劳设置类 * @author RJH * create at 2019-03-26 */ @EnableAsync @Configuration public class AsyncConfig { }
异步事宜监听
import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; /** * 异步事宜监听 * @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()); } }
运转效果
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) ...内容太长省略部份效果
剖析:革新为异步实行后,事宜监听就由线程池举行处置惩罚,此处还能够经由过程自定义线程池,并设置非常处置惩罚器来处置惩罚未捕捉的非常。
本篇文章到这里就已悉数完毕了,更多其他精彩内容能够关注ki4网的Java视频教程栏目!
以上就是Spring事宜机制题目排查的要领引见的细致内容,更多请关注ki4网别的相干文章!