java - 在 java.lang.reflect.Proxy 对象上调用扩展函数时的 Kotlin 奇怪行为

标签 java kotlin reflection dynamic-proxy extension-function

今天我在 Kotlin 中玩了一些 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 调用都会调用这个时间吗?

最佳答案

这就是所谓的自调用,并且是基于代理的 AOP(例如 Spring 的 @Transactional@Cacheable)中错误的重要来源)。

您的 Proxy Dog 用作底层 DogImpl 实例的装饰器。当您的主方法调用 proxyDog.bark5Times() 时,扩展方法在代理对象上连续调用 bark() 五次,这包含建议并因此打印您的“代理调用!”消息。

但是,当您调用 bark3Times() 时,该调用会触发代理(打印日志消息!)...然后 DogImpl 实例调用 this .bark() 直接 三次,不通过代理。

关于java - 在 java.lang.reflect.Proxy 对象上调用扩展函数时的 Kotlin 奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55553411/

相关文章:

java - Kotlin 中 @BeforeAll 的正确解决方法是什么

annotations - KAPT(Kotlin 注解处理)支持 Kotlin-JS 吗?

c# - 将正确的类型参数传递给 MethodInfo GetMethod

java - 获取类型对象的值

java - 如何将反射字段类型转换为另一个对象?

java - 如何使用 Java 从两个 for 循环中获取单独的输出

java - 使用 root loader 加载 jar

date - 在 Kotlin 中计算日期

java - 我正在制作一个24小时时钟

java - 从 Lambda 函数(Java 运行时)发布 SNS 消息