我的Spring应用中返回@Async
(或void
,我在Kotlin写作)的Unit
方法有点问题。
我不知道为什么,但当@Async
方法返回void
时,它只是没有执行,或者至少它没有做到它应该做的事情。需要说明的是,在我的异步方法中,我想使用JavaMailSender
发送电子邮件,所以没什么大不了的。这是方法:
@Async
override fun sendEmail(locale: Locale, subject: String, message: String, to: String) {
val msg = sender.createMimeMessage()
println("1")
val helper = MimeMessageHelper(msg, true, "utf-8")
helper.setFrom("email@example.com")
helper.setTo(to)
println("2")
helper.setSubject(getSubject(locale, null))
println("3")
helper.setText(processTemplate(locale, null, null), true)
println("4")
sender.send(msg)
println("5")
}
但是电子邮件永远不会出现,没有异常记录(我正在运行testNG测试)。
当我更改函数的签名以使其返回Future<String>
并在函数末尾添加一些虚拟返回行然后我调用service.sendEmail(...).get()
时,该方法的主体神奇地执行,电子邮件到达。
在我的@Configuration
课程中,有@EnableAsync
。我还实现了AsyncConfigurer
并提供了自己的执行器和异常处理程序,因为我认为它可能是我的执行器bean定义的东西,但没有任何帮助。
这让我发疯,因为我只是想在后台默默地执行某些事情并且它不起作用。默默地说,我的意思是我不想被内部异常所困扰。
你有什么想法吗?
更新
所以@pleft建议,我在我的方法中放了一些打印件。
现在,当我运行mvn clean test
时,我可以看到每次都打印1,2,3,但。有时只打印1和2。我也在我的AsyncUncaughtExceptionHandler
中打印,但是没有打印。
看起来背景线程太快被杀死了。
更新2:
我的服务配置:
@Configuration
@EnableScheduling
@EnableAsync
@ComponentScan
class ServiceConfig : ApplicationContextAware, EnvironmentAware, AsyncConfigurer {
override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler {
return AsyncUncaughtExceptionHandler { ex, method, params ->
println("Exception thrown")
}
}
override fun getAsyncExecutor(): Executor {
val executor = ThreadPoolTaskExecutor()
executor.corePoolSize = 2
executor.maxPoolSize = 2
executor.setQueueCapacity(500)
executor.threadNamePrefix = "asyncThread"
executor.initialize()
return executor
}
}
/// other beans definitions..
也许这很重要,也许不是,但我在processTemplate
方法中使用了Thymeleaf。
答案 0 :(得分:3)
基于评论中的对话和我自己的观察(比如在测试方法中放一些睡眠),我发现了原因。这是因为测试中的Spring Context被破坏了。因为我只有一个测试运行这个异步方法,所以情况是async方法立即返回,测试方法也是如此。因为它是我的测试套件中的最后一个(也是唯一的)方法,所以测试上下文被破坏(以及它创建的所有线程)。
所以解决方案是要么把睡眠放在测试中(非常难看),要么看看this question并获得灵感。