Kotlin在java上调用扩展函数时的奇怪行为。朗,反思一下。代理对象
今天我在科特林和一些java.lang.reflect.Proxy
玩,我对这种行为感到惊讶:
import java.lang.reflect.Proxy
interface Dog {
fun bark()
fun bark3Times()
}
class DogImpl : Dog {
override fun bark() = println("Bark!")
override fun bark3Times() = repeat(3) { bark() }
}
fun Dog.bark5Times() = repeat(5) { bark() }
fun main(args: Array<String>) {
val classLoader = Dog::class.java.classLoader
val realDog: Dog = DogImpl()
val proxyDog: Dog = Proxy.newProxyInstance(
classLoader,
arrayOf(Dog::class.java)
) { _, method, _ ->
println("Proxy invoked! Method = ${method.name}")
method.invoke(realDog)
} as Dog
println("--- Dog barking 3 times ---")
proxyDog.bark3Times()
println()
println("--- Dog barking 5 times ---")
proxyDog.bark5Times()
}
输出:
--- Dog barking 3 times ---
Proxy invoked! Method = bark3Times
Bark!
Bark!
Bark!
--- Dog barking 5 times ---
Proxy invoked! Method = bark
Bark!
Proxy invoked! Method = bark
Bark!
Proxy invoked! Method = bark
Bark!
Proxy invoked! Method = bark
Bark!
Proxy invoked! Method = bark
Bark!
问题:
为什么在第一个示例中,只为bark3Times
调用调用代理,而不为单独的bark
调用代理,但在第二个示例中,不为bark5Times
调用代理,而是为每个bark
调用代理
# 1 楼答案
这就是所谓的自调用,是基于代理的AOP(例如Spring的
@Transactional
和@Cacheable
)中大量错误的来源您的
Proxy
Dog
正在充当底层DogImpl
实例的装饰器。当主方法调用proxyDog.bark5Times()
时,扩展方法在代理对象上连续调用bark()
五次,该代理对象包含建议,因此打印“代理已调用!”留言但是,当您调用
bark3Times()
时,该调用会命中代理(日志消息已打印!)。。。然后DogImpl
实例直接对自身调用this.bark()
三次,而不是通过代理# 2 楼答案
你的困惑源于对扩展函数的误解。它们被编译成JVM中的静态方法,而不是神奇地“注入”到类中。当您意识到它们看起来像Java代码时,问题就变得显而易见了: