xin*_*aiz 3 java reflection dynamic-proxy kotlin extension-function
今天,我java.lang.reflect.Proxy在科特林(Kotlin)和一些人一起玩耍,对此行为感到惊讶:
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()
}
Run Code Online (Sandbox Code Playgroud)
输出:
--- 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!
Run Code Online (Sandbox Code Playgroud)
问题:
为什么在第一个示例中,仅针对bark3Times呼叫而不是单独的bark呼叫调用代理,而在第二个示例中,为什么不针对调用,但是bark5Times每次bark调用都调用Proxy ?
这就是所谓的自我调用,是基于代理的AOP(例如Spring @Transactional和@Cacheable)中大量bug的来源。
您Proxy Dog正在充当基础DogImpl实例的装饰器。当您的main方法调用时proxyDog.bark5Times(),扩展方法在代理对象上bark()连续调用五次,该对象包含建议,并因此打印“代理调用!” 信息。
但是,当您调用时bark3Times(),该调用会命中代理(已打印日志消息!)...,然后DogImpl实例this.bark() 直接调用自身 3次,而不通过代理。