Kotlin奇妙な行動のjava.lang.reflect.Proxyオブジェクトの拡張機能を呼び出すとき

xinaiz:

今日、私はいくつかでプレイjava.lang.reflect.ProxyKotlinに、私はこの振る舞いに驚きました。

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() 自体に直接三回は、プロキシを経由しません。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=200945&siteId=1