使用Java动态代理拦截挂起函数

时间:2019-03-02 08:26:42

标签: kotlin proxy suspend

以下代码使用功能[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核心团队的成员?

您可以在https://github.com/softappeal/yass/blob/master/kotlin/yass/test/ch/softappeal/yass/demo/DynamicProxyDemo.kt

中找到完整的代码

我在服务框架中使用它来与Ktor实施非阻塞调用。

0 个答案:

没有答案