xinaiz:
今日、私はいくつかでプレイ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()
}
出力:
--- 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
のコールが、2番目の例では、それが求めていないbark5Times
が、今回はすべてのために呼ばれるbark
コール?
chrylis -on strike-:
これは、として知られているものである自己コールと(例えばSpringのようプロキシベースのAOPのバグの実質的な供給源である@Transactional
と@Cacheable
)。
あなたはProxy
Dog
根本的にデコレータとして機能しているDogImpl
インスタンス。あなたの主なメソッド呼び出しがときにproxyDog.bark5Times()
、拡張メソッドを呼び出すbark()
行に5回、プロキシオブジェクトのアドバイスが含まれているので、印刷し、あなたの「プロキシが呼び出されました!」メッセージ。
しかし、あなたが呼び出すときに、bark3Times()
そのコールは(ログメッセージが印刷された!)プロキシをヒット...そしてDogImpl
、インスタンスの呼び出しthis.bark()
自体に直接三回は、プロキシを経由しません。