以下代码使用功能[sProxy]拦截暂停功能。
它打印:
add[1, 2] called
3
代码
typealias SInvocation = suspend () -> Any?
typealias SInterceptor =
suspend (method: Method, args: List<Any?>, invocation: SInvocation) -> Any?
interface Calculator {
suspend fun add(a: Int, b: Int): Int
}
class CalculatorImpl : Calculator {
override suspend fun add(a: Int, b: Int) = a + b
}
val Printer: SInterceptor = { method, args, invocation ->
println("${method.name}$args called")
invocation()
}
fun main() = runBlocking {
val calculator = sProxy(Calculator::class.java, CalculatorImpl(), Printer)
println(calculator.add(1, 2))
}
以下代码显示了[sProxy]函数的有效实现:
interface SFunction {
suspend fun invoke(): Any?
}
val SRemover: Method = SFunction::class.java.methods[0]
typealias SInvoker = suspend (method: Method, args: List<Any?>) -> Any?
fun Method.sInvoke(
args: List<Any?>, continuation: Continuation<*>, invoker: SInvoker
): Any? = SRemover.invoke(object : SFunction {
override suspend fun invoke(): Any? = invoker(this@sInvoke, args)
}, continuation)
suspend fun Method.sInvoke(implementation: Any, args: List<Any?>): Any? =
suspendCoroutineUninterceptedOrReturn { continuation ->
sInvoke(args, continuation) { _, _ ->
invoke(implementation, *args.toTypedArray(), continuation)
}
}
/** Creates a proxy for [sContract] that intercepts calls to [implementation]. */
@Suppress("UNCHECKED_CAST")
fun <C : Any> sProxy(
sContract: Class<C>, implementation: C, interceptor: SInterceptor
): C = Proxy.newProxyInstance(
sContract.classLoader, arrayOf(sContract)
) { _, method, args ->
method.sInvoke(
args.take(args.size - 1), args.last() as Continuation<*>
) { _, params ->
interceptor(method, params) { method.sInvoke(implementation, params) }
}
} as C
所以现在的问题是: -这是一个好的/问题解决方案吗? -有更好的解决方案吗?
反馈将受到高度赞赏, 也许甚至来自Kotlin核心团队的成员?
中找到完整的代码我在服务框架中使用它来与Ktor实施非阻塞调用。