3

@Async在我的 Spring 应用程序中返回void(或者Unit,我正在用 Kotlin 编写)的方法有一点问题。

我不知道为什么,但是当@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。我也把 print 放在我的 中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。

4

1 回答 1

3

根据评论中的对话和我自己的观察(比如在测试方法中加入一些睡眠),我找到了原因。这是由于测试中的 Spring Context 被破坏造成的。因为我只有一个测试运行这个异步方法,所以场景是异步方法立即返回,测试方法也是如此。由于它是我的测试套件中的最后一个(也是唯一一个)方法,因此测试上下文被破坏(以及它创建的所有线程)。

因此,解决方案是要么在测试中睡觉(非常丑陋),要么看看这个问题并获得启发。

于 2017-09-14T20:21:18.423 回答