Kotlin extraño comportamiento cuando se llama a la función de extensión en el objeto java.lang.reflect.Proxy

xinaiz:

Hoy he jugado con un poco java.lang.reflect.Proxyde Kotlin, y me sorprendió por este comportamiento:

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()

}

Salida:

--- 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!

La pregunta:

¿Por qué en primer ejemplo proxy se llama sólo para bark3Timesllamadas y no para separar barklas llamadas, pero en segundo ejemplo no se llama para bark5Times, pero esta vez se llama para cada barkllamada?

chrylis -on tachado:

Esto es lo que se conoce como auto-llamada y es una fuente importante de errores en AOP basado en proxy (como la primavera de @Transactionaly @Cacheable).

Su Proxy Dogestá sirviendo como decorador a un subyacente DogImplejemplo. Cuando sus principales llamadas de método proxyDog.bark5Times(), el método de extensión llama bark()cinco veces seguidas en el objeto proxy , que contiene el consejo y por lo tanto se imprimen su "proxy invoca!" mensaje.

Sin embargo, cuando se llama bark3Times(), esa llamada golpea el proxy (mensaje de registro impreso!) ... y luego las DogImplllamadas de instancia this.bark() sobre sí directamente tres veces, no pasa por el proxy.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=200948&siteId=1
Recomendado
Clasificación