Issue with a Spring @Async method not catching/rethrowing an exception

匿名 (未验证) 提交于 2019-12-03 00:56:02

问题:

I am facing an issue since I enabled turned a synchronous method into an asynchronous one: if an exception is thrown from within the body of the method, I can no longer rethrow it.

Let me first show the code:

My async/task executor configuration:

@Configuration @EnableAsync public class AsyncConfiguration implements AsyncConfigurer {      @Override     public Executor getAsyncExecutor() {         ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();         taskExecutor.setCorePoolSize(5);         taskExecutor.setMaxPoolSize(10);         taskExecutor.setQueueCapacity(25);         taskExecutor.initialize();         return taskExecutor;     } } 

My asynchronous method:

@Async @Override public void sendPasswordResetInfo(String email) {     Assert.hasText(email);     Member member = memberRepository.findByEmail(email);     try {         mailerService.doMailPasswordResetInfo(member);//EXCEPTION THROWN HERE     } catch (MessagingException | MailSendException e) {         log.error("MessagingException | MailSendException", e);         // TODO: not thrown since @Async is used         throw new MailerException("MessagingException | MailSendException");//NOT CALLED     } } 

All I see in the console when an exception is raised by mailerService.doMailPasswordResetInfo is the following stacktrace:

2014-06-20 18:46:29,249 [ThreadPoolTaskExecutor-1] ERROR com.bignibou.service.preference.PreferenceServiceImpl - MessagingException | MailSendException org.springframework.mail.MailSendException: Failed messages: javax.mail.SendFailedException: Invalid Addresses;   nested exception is:     com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 Adresse d au moins un destinataire invalide. Invalid recipient. OFR204_418 [418] ; message exception details (1) are: Failed message 1: javax.mail.SendFailedException: Invalid Addresses;   nested exception is:     com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 Adresse d au moins un destinataire invalide. Invalid recipient. OFR204_418 [418]      at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1294)     at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:635)     at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:424)     at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:346)     at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:341)     at com.bignibou.service.mailer.MailerServiceImpl.doMailPasswordResetInfo(MailerServiceImpl.java:82)     at com.bignibou.service.preference.PreferenceServiceImpl.sendPasswordResetInfo_aroundBody10(PreferenceServiceImpl.java:112)     at com.bignibou.service.preference.PreferenceServiceImpl$AjcClosure11.run(PreferenceServiceImpl.java:1)     at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.aj:59)     at org.springframework.transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:65)     at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)     at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:63)     at com.bignibou.service.preference.PreferenceServiceImpl.sendPasswordResetInfo_aroundBody12(PreferenceServiceImpl.java:108)     at com.bignibou.service.preference.PreferenceServiceImpl$AjcClosure13.run(PreferenceServiceImpl.java:1)     at org.springframework.scheduling.aspectj.AbstractAsyncExecutionAspect.ajc$around$org_springframework_scheduling_aspectj_AbstractAsyncExecutionAspect$1$6c004c3eproceed(AbstractAsyncExecutionAspect.aj:58)     at org.springframework.scheduling.aspectj.AbstractAsyncExecutionAspect.ajc$around$org_springframework_scheduling_aspectj_AbstractAsyncExecutionAspect$1$6c004c3e(AbstractAsyncExecutionAspect.aj:62)     at com.bignibou.service.preference.PreferenceServiceImpl.sendPasswordResetInfo(PreferenceServiceImpl.java:108)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     at java.lang.reflect.Method.invoke(Method.java:483)     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)     at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)     at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:97)     at java.util.concurrent.FutureTask.run(FutureTask.java:266)     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)     at java.lang.Thread.run(Thread.java:745) Caused by: com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 Adresse d au moins un destinataire invalide. Invalid recipient. OFR204_418 [418]      at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1145)     ... 28 more 

FYI, MailerException is a custom exception I used in the app. What really strikes me is that this MailerException exception does not appear to be caught nor rethrown...

Can anyone please help?

edit 1: I have modified my async service method as follows:

@Async     @Override     public Future<Void> sendPasswordResetInfo(String email) {         Assert.hasText(email);         Member member = memberRepository.findByEmail(email);         try {             mailerService.doMailPasswordResetInfo(member);             return new AsyncResult<Void>(null);         } catch (MessagingException | MailSendException e) {             log.error("MessagingException | MailSendException", e);             //HERE: HOW DO I SEND THE MailerException USING THE FUTURE??             throw new MailerException("MessagingException | MailSendException");         }     } 

However, I am not sure how to send the MailerException to the web layer using the AsyncResult from within the catch block above...

回答1:

Your logs show

2014-06-20 18:46:29,249 [ThreadPoolTaskExecutor-1] ERROR com.bignibou.service.preference.PreferenceServiceImpl - MessagingException | MailSendException 

which is logged by

log.error("MessagingException | MailSendException", e); 

the Exception that is then thrown

throw new MailerException("MessagingException | MailSendException");//NOT CALLED 

is caught by the Thread executed by the underlying ThreadPoolTaskExecutor. This code is run asynchronously so the exception is thrown in a different thread then the thread that invokes the method.

someCode(); yourProxy.sendPasswordResetInfo(someValue()); // exception thrown in other thread moreCode(); 

If you make your method return a Future as shown here you'll be able to invoke get() on it and that will rethrow any exception that was thrown inside the @Async method, wrapped in an ExecutionException.



回答2:

By following this link http://www.baeldung.com/spring-async, you should create:

  1. CustomAsyncExceptionHandler that implements AsyncUncaughtExceptionHandler

     @Slf4j public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {   @Override   public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {     log.error("**********************************************");     log.error("Exception message - " + throwable.getMessage());     log.error("Method name - " + method.getName());     for (Object param : obj) {         log.error("Parameter value - " + param);     }     log.error("**********************************************");   } } 
  2. SpringAsyncConfig that implements AsyncConfigurer

     @Configuration @EnableAsync public class SpringAsyncConfig implements AsyncConfigurer {    @Override   public Executor getAsyncExecutor() {     return new ThreadPoolTaskExecutor();   }    @Override   public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {     return new CustomAsyncExceptionHandler();   } } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!