【问题标题】:Groovy getProperties() call invoking getter for non-existent attribute over 1000 timesGroovy getProperties() 调用为不存在的属性调用 getter 超过 1000 次
【发布时间】:2016-04-28 00:02:37
【问题描述】:

在进行重构时遇到了这个问题。对 getProperties() 的调用导致我们的 CPU 使用率飙升。我们发现,如果您有一个没有关联属性的 getter,当您调用 getProperties() 时,该 getter 会被调用超过 1000 次。修复/解决方法很明显,我们知道它与元编程有关,但为什么会发生这种情况(groovy 源代码中的哪一点)?请参阅下面的 groovy 脚本代码:

class tester {

    int count = 0

    public getVar() {
       println count++ + " getVar() called!"
       return var
    }
}

def t = new tester()

t.getProperties()

println "done!"

您应该看到 getVar() 被调用超过 1000 次。 1068 对我们来说是准确的。

【问题讨论】:

  • 很奇怪。我刚刚在 groovy web 控制台groovyconsole.appspot.com 中尝试了这个,我看到它执行了 110 次。
  • 因为return var 这一行而发生。这实际上是在递归调用getVar() 本身,因为return var 与调用return getVar() 相同。它会打印计数,直到堆栈溢出。
  • return var 是问题所在。
  • 为了完整起见:docs.groovy-lang.org/latest/html/documentation/…(我知道var字段没有在类中定义)。
  • 更改 return var 以返回 this.@var 与众不同

标签: grails groovy metaprogramming


【解决方案1】:

这个问题可能已经在 cmets 中得到了回答,但我更深入地回答了“groovy 源代码中的什么点”部分。

当您在 tester 的实例上调用 getProperties() 时,Groovy 会发挥它的魔力,最后调用 DefaultGroovyMethods#getProperties(Object)(在 Groovy 2.4.7 中)如下所示:

public static Map getProperties(Object self) {
    List<PropertyValue> metaProps = getMetaPropertyValues(self); // 1
    Map<String, Object> props = new LinkedHashMap<String, Object>(metaProps.size());

    for (PropertyValue mp : metaProps) {
        try {
            props.put(mp.getName(), mp.getValue()); // 2
        } catch (Exception e) {
            LOG.throwing(self.getClass().getName(), "getProperty(" + mp.getName() + ")", e);
        }
    }
    return props;
}

首先,Groovy 确定给定对象的元属性(参见 1)。这将返回三个属性:

  • var:只有 getter (getVar()),没有 setter,没有字段
  • class:只有getter(继承自Object),没有setter,没有字段
  • count:getter、setter(均由 Groovy 生成)和字段

您可以通过调用t.getMetaPropertyValues() 轻松验证这一点。

接下来,Groovy 尝试获取每个属性的当前值并将其放入映射中(参见 2)。当它到达var 时,它会记住var 有一个getter(即getVar())并调用它。 getVar() 但是,再次返回 var。对于 Groovy,这与第一步中确定的属性完全相同。再次调用它的 getter getVar() 并开始无限循环。

在某些时候,取决于 JVM,这会导致 StackOverflowError,这正是这个网站的全部内容:-D

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-28
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 2011-05-15
    • 1970-01-01
    • 2015-10-01
    相关资源
    最近更新 更多