java - 在 java.lang.reflect.Proxy 对象上调用扩展函数时 Kotlin 的奇怪行为
问题描述
今天我在 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
)中 bug 的重要来源。
您Proxy
Dog
正在充当底层DogImpl
实例的装饰器。当您的 main 方法调用proxyDog.bark5Times()
时,扩展方法在代理对象上bark()
连续调用五次,其中包含建议并因此打印您的“代理调用!” 信息。
但是,当您调用 时bark3Times()
,该调用会命中代理(打印日志消息!)......然后DogImpl
实例this.bark()
直接调用自身3 次,而不通过代理。
推荐阅读
- mongodb - 如何使用 Groovy 在 mongo 中插入双精度类型值?
- python - 正确使用 processName LogRecord 属性
- python - 使用 Python BeautifulSoup 抓取表格时遇到问题
- python - 检测时间序列的快速增长
- kubernetes - 为什么 Istio 要求 Pod 至少属于 Kubernetes 中的一个 Service?
- java - 将 Java Gradle 多项目推送到 Git
- python - Msys2 无法使用 python + qt5 解决依赖关系
- html - 如何使用引导程序在移动设备上创建响应式 HTML?
- sql-server - 使用条件列表 SQL Server (UPDLOCK, READPAST, ROWLOCK)
- apache-spark - 在远程配置单元上运行 sql 查询时出现未知主机错误