我正在尝试创建一个异步执行操作的Spring Service并返回router.post('/login'...
。我希望在操作失败时触发失败回调 - 我尝试这样做是为了使用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)
}
}
}
Spring RestController实现如下:
@SpringBootApplication
@EnableAsync
open class UserProxyApplication
fun main(args: Array<String>) {
SpringApplication.run(UserProxyApplication::class.java, *args)
}
问题是在@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;
}
}
REST调用中抛出异常时,永远不会触发UserController
中的失败回调。相反,成功回调是在UserClientService
参数为success
的情况下触发的。
在Kotlin中,我可以使用null
检查成功是否为空 - 这会引发异常,然后 触发故障回调,其中success!!
参数为NPE。
问题是如何在failure
中发生异常时触发UserController
中的失败回调?
更新A 似乎所有内容都在同一个线程“http-nio-8080-exec-XXX”上执行,无论我是否使用UserClientService
- 请参阅注释。
答案 0 :(得分:1)
这一切都适用于:
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。我见过的例子并不需要实现一个界面。