异步 Spring 使用 Kotlin 启动不工作
Async Spring Boot using Kotlin not working
我正在尝试创建一个 Spring 异步执行操作的服务和 returns 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)
}
SpringRestController实现如下:
@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 是否为 null - 这会抛出一个异常,然后 确实 使用 failure
触发失败回调参数是 NPE。
问题是UserClientService
异常时如何触发UserController
的失败回调?
更新 A 似乎一切都在同一个线程上执行 "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。我看到的示例不需要实现接口。
我正在尝试创建一个 Spring 异步执行操作的服务和 returns 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)
}
SpringRestController实现如下:
@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 是否为 null - 这会抛出一个异常,然后 确实 使用 failure
触发失败回调参数是 NPE。
问题是UserClientService
异常时如何触发UserController
的失败回调?
更新 A 似乎一切都在同一个线程上执行 "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。我看到的示例不需要实现接口。