这个问题不是寻找问题的解决方案,而是解释为什么可能出现问题(或不是!)。
Class.getMethods()
的{{3}}说:
返回的数组中的元素没有排序,也没有任何特定的顺序。
问题是:我们一直在使用一个名为Javadocs的整洁的小Java模板库,可能已经有几年了,没有任何问题。这使用类似JSTL的语法将模型值注入模板。特别是,我们一直在使用这样的东西来代价:
${vendor.currency.symbol} ${order.amount}
其中第一个转换为以下内容:
vendor.getCurrency().getSymbol()
其中getCurrency()
返回JMTE个对象。货币有两种获取货币符号的方法 - 一种采用特定的Locale,另一种采用默认的。
过去18个月左右,一切运行正常,电子邮件中出现货币代码/符号。然后5天前,当我们尝试替换IllegalArgumentException
时,我们开始随机${vendor.currency.symbol}
经过一些调试后,我找到了原因,深入JMTE:
for (Method method : declaredMethods) {
if (Modifier.isPublic(method.getModifiers())
&& (method.getName().equals("get" + suffix) ||
method.getName().equals("is" + suffix))) {
value = method.invoke(o, (Object[]) null);
....
}
}
即,getSymbol()
或getSymbol(Locale)
是否被调用完全取决于Class.getMethods()
的返回顺序(不按任何特定顺序)。我添加了一个测试,以确保方法有0参数,我的问题解决了。
现在,由于一个奇怪的巧合,其他人碰巧在我们第一次观察到这种行为的同一天提交了public String getSymbol(Locale locale)
。
令人费解的是,这段代码已经运行了18个月而没有任何问题,然后突然出现这种情况。
当我创建一个测试用例时,它大约有50%的时间失败,正如人们所期望的那样(有两种匹配的方法,没有特定的顺序返回),所以我感到困惑(惊讶)它适用于18几个月和10 ^ 5次执行。 (可以想象,但不太可能,它已经失败但在随后的重试中取得了成功)。
完全出于好奇,我想知道Java运行时中是否有任何可能导致此潜在行为突然出现的内容。更令人费解的是,在同一天,其他人应该为一个成熟稳定的项目提供这种行为的解决方案 - 这可能意味着同样的潜在行为突然在其他地方实现了。
所以,问题是:有没有人知道哪些因素可能会影响Class.getMethods()
返回的方法的顺序?
答案 0 :(得分:2)
可以从getMethods()
看到的相关Java代码显示了对缓存数据的大量检查,但最后的说法取决于此实现:
private native Method[] getDeclaredMethods0(boolean publicOnly);
因此,它依赖于虚拟机,并且仅仅因为"它很多次都是相同的而非常糟糕的想法"。
缓存肯定会影响它,因为如果它第一次正确获取,它将在随后的时间工作,除非缓存被清除(有一些软参考业务和这样下去。)