kotlin如何配合动态代理使用

大多数有经验的开发人员都熟悉使用动态代理。它们使我们能够在运行时实现接口,并决定如何在调用方法时动态执行方法。这对于围绕Decorator模式所描述的现有实现(尤其是来自第三方库)添加额外功能非常有用。然而,Kotlin协程在创建动态代理时引入了一组新的问题。

以下为未例代码

class CorrectExceptionLogger<T>(private val instance: T): InvocationHandler {
    override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
        val nonNullArgs = args ?: arrayOf()
        try {
            val lastArg = nonNullArgs.lastOrNull()
            if(lastArg == null || lastArg !is Continuation<*>) {
                // not a suspend func, just invoke regularly
                return method?.invoke(instance, *nonNullArgs)
            } else {
                // Step 1: Wrap the underlying continuation to intercept exceptions.
                @Suppress("UNCHECKED_CAST")
                val originalContinuation = lastArg as Continuation<Any?>
                val wrappedContinuation = object: Continuation<Any?> {
                    override val context: CoroutineContext get() = originalContinuation.context
                    override fun resumeWith(result: Result<Any?>) {
                        result.exceptionOrNull()?.let{ err ->
                            // Step 2: log intercepted exception and resume with our custom wrapped exception.
                            println("Correctly caught underlying coroutine exception $err")
                            originalContinuation.resumeWithException(WrappedTestException(err))
                        } ?: originalContinuation.resumeWith(result)
                    }
                }
                // Step 3: launch the suspend function with our wrapped continuation using the underlying scope and context, but force it to run in the IO thread pool
                CoroutineScope(originalContinuation.context).launch(Dispatchers.IO + originalContinuation.context) {
                    val argumentsWithoutContinuation = nonNullArgs.take(nonNullArgs.size - 1)
                    val newArgs = argumentsWithoutContinuation + wrappedContinuation
                    method?.invoke(instance, *newArgs.toTypedArray())
                }
                return kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
            }
        } catch(e: InvocationTargetException) {
            e.targetException?.let{ targetException ->
                println("Correctly caught underlying exception $targetException")
                throw WrappedTestException(targetException)
            } ?: throw WrappedTestException(e)
        }
    }
}

你可能感兴趣的:(Andorid,kotlin,android,开发语言)