测试Spring的@Async void-returns方法

时间:2017-09-14 19:34:32

标签: java spring spring-mvc kotlin spring-async

我的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。

1 个答案:

答案 0 :(得分:3)

基于评论中的对话和我自己的观察(比如在测试方法中放一些睡眠),我发现了原因。这是因为测试中的Spring Context被破坏了。因为我只有一个测试运行这个异步方法,所以情况是async方法立即返回,测试方法也是如此。因为它是我的测试套件中的最后一个(也是唯一的)方法,所以测试上下文被破坏(以及它创建的所有线程)。

所以解决方案是要么把睡眠放在测试中(非常难看),要么看看this question并获得灵感。