异步春季启动使用Kotlin无法正常工作

我正在尝试创建一个异步执行操作的Spring服务,并返回一个ListenableFuture 。 我希望在操作失败时触发失败回调 – 我尝试这样做是使用AsyncResult.forExecutionException ,如下所示:

 @Service open class UserClientService { @Async fun fetchUser(email: String): ListenableFuture<User> { val uri = buildUri(email) val headers = buildHeaders() try { val result = restTemplate.exchange(uri, HttpMethod.GET, HttpEntity<Any>(headers), User::class.java) return AsyncResult.forValue(result.body) } catch (e: RestClientException) { return AsyncResult.forExecutionException(e) } } } 

入门点:

 @SpringBootApplication @EnableAsync open class UserProxyApplication fun main(args: Array<String>) { SpringApplication.run(UserProxyApplication::class.java, *args) } 

Spring的RestController实现如下:

 @RestController @RequestMapping("/users") class UserController @Autowired constructor( val client: UserClientService ) { @RequestMapping(method = arrayOf(RequestMethod.GET)) fun getUser(@RequestParam(value = "email") email: String): DeferredResult<ResponseEntity<User>> { val result = DeferredResult<ResponseEntity<User>>(TimeUnit.SECONDS.toMillis(10)) client.fetchUser(email).addCallback( { success -> result.setResult(ResponseEntity.ok(success)) }, { failure -> result.setResult(ResponseEntity(HttpStatus.NOT_FOUND)) } ) return result; } } 

问题是在UserClientService REST调用中引发异常时, UserController中的失败回调从不触发。 相反,成功回调是由success参数为null触发的。

在Kotlin,我可以通过success!!检查成功是否为空success!! – 这会抛出一个异常,然后用failure参数作为NPE触发失败回调。

问题是如何在UserClientService发生异常时触发UserController的失败回调?

更新一个似乎是所有的东西都在同一个线程“http-nio-8080-exec-XXX”上执行,不管我是否使用@Async或者不是 – 请参阅注释。

这一切工作如果:

A)方法fetchUser被声明为open ,即不是最终的,以便Spring可以代理该呼叫

…要么…

B)你创建一个接口IUserClientService并在UserController的构造函数中使用它:

 interface IUserClientService { fun fetchUser(email: String): ListenableFuture<User> } 

现在UserClientService实现这个接口:

 @Service open class UserClientService : IUserClientService { @Async override fun fetchUser(email: String): ListenableFuture<User> { // ... rest as shown in question ... 

最后是UserController

 @RestController @RequestMapping("/users") class UserController @Autowired constructor( val client: IUserClientService ) { @RequestMapping(method = arrayOf(RequestMethod.GET)) fun getUser(@RequestParam(value = "email") email: String): DeferredResult<ResponseEntity<User>> { // ... rest as shown in question ... 

不知道这是因为我在使用Kotlin。 我见过的例子不需要实现一个接口。