使用 Byte Buddy 的建议 API,是否可以从检测的方法返回而不实际执行它?
一个用例是实现缓存并返回缓存值(如果存在),而不是再次计算该值。
@Advice.OnMethodEnter
public static Object returnCachedValue(@Advice.Argument(0) String query) {
if (cache.containsKey(query)) {
// should "abort" method call
return cache.get(query);
}
}
我知道上面的代码示例只是创建了一个局部变量,我可以在
@Advice.OnMethodExit
方法中获取它。但是有没有办法在显式 return
上中止方法调用?如果是,这也适用于 void
方法吗?
不,这是不可能的,返回值只能从退出建议中设置。但是,如果值已经存在,则可以通过跳过原始方法来模拟;如果输入建议定义了值,则可以通过从退出建议中设置该值来模拟:
class MyAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static Object returnCachedValue(@Advice.Argument(0) String query) {
if (cache.containsKey(query)) {
return cache.get(query);
} else {
return null;
}
}
@Advice.OnMethodExit
public static void processCachedValue(
@Advice.Argument(0) String query,
@Advice.Return(readOnly = false, typing = DYNAMIC) Object returned,
@Advice.Enter Object enter) {
if (enter != null) {
returned = enter;
} else {
cache.put(query, returned);
}
}
}
当然,如果缓存的值为
null
,则此方法不起作用。为了避免这种情况,您可以将值包装在某个实例中,以确保输入值永远不会是 null
。这样做还可以将上述模式用于 void
方法。
这可能看起来不方便编程,但建议的想法是 Byte Buddy 可以使用建议类作为模板并内联字节代码,无需太多工作即可避免运行时开销。