使用Byte Buddy拦截对Java 8 lambda表达式的调用 [英] Intercepting calls to Java 8 lambda-expressions using Byte Buddy

查看:332
本文介绍了使用Byte Buddy拦截对Java 8 lambda表达式的调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用Byte Buddy AgentBuilder 拦截对方法的调用和对Java 8 lambda表达式的调用,如下所示:

I try to intercept calls to methods and calls to Java 8 lambda expressions using a Byte Buddy AgentBuilder as follows:

static {
  final Instrumentation inst = ByteBuddyAgent.install();
  new AgentBuilder.Default()
        .type(ElementMatchers.nameContainsIgnoreCase("foo"))
        .transform((builder, typeDescription) ->
                builder.method(ElementMatchers.any())
                        .intercept(MethodDelegation.to(LogInterceptor.class)))
        .installOn(inst);
}

public static class LogInterceptor {
  @RuntimeType
  public static Object log(@SuperCall Callable<?> superCall) throws Exception {
    System.out.println("yeah...");
    return superCall.call();
  }
}

我正在使用Byte Buddy v0.7.1。

I'm using Byte Buddy v0.7.1.

它可以拦截以下 Runnable (匿名类):

It can intercept the following Runnable (anonymous class):

FunnyFramework.callMeLater(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello from inner class");
    }
});

当然还有对定义为 normal 的对象的任何调用(非匿名)类。但是该拦截不适用于lambda表达式,例如:

and of course any calls to objects defined as normal (non-anonymous) classes. But the interception does not work for lambda expression's like:

FunnyFramework.callMeLater(() -> {
    System.out.println("Hello from lambda");
});

如何截获lambda表达式调用?据我所知,在字节好友中没有 LambdaInterceptor 这样的东西。

How can I intercept also the lambda expression calls? There's no such thing as a LambdaInterceptor in Byte Buddy, as far as I know.

推荐答案

Java虚拟机不允许转换表示lambda表达式的类文件。表示lambda表达式的类由所谓的 匿名类加载器 加载a>(不要与经典 匿名类 ),它继承了另一个类的安全上下文,例如使用匿名类加载器加载的类,该类将加载的类绑定到另一个类 Foo 可以访问 private 的方法 Foo 。此加载使用 sun.misc.Unsafe API明确进行。

The Java virtual machine does not permit a transformation of a class files representing a lambda expression. Classes that represent lambda expressions are loaded by so-called anonymous class loaders (not to be confused with classical anonymous classes) that inherit another class's security context, e.g. a class that is loaded with an anonymous class loader which binds the loaded class to another class Foo can access private methods of Foo. This loading happens explicitly using the sun.misc.Unsafe API.

Byte Buddy钩子插入 Java工具API ,允许应用 ClassFileTransformer 挂接到 ClassLoader 的加载过程。由于匿名类加载器在一般意义上不被视为 ClassLoader ,因此插装API不允许此类插装,因此禁止对lambda进行插装。

Byte Buddy hooks into the Java instrumentation API which allows the application of ClassFileTransformers to hook into a ClassLoaders loading process. As anonymous class loaders are not considered ClassLoaders in the common sense, the instrumentation API does not allow for such instrumentations and therefore prohibits the instrumentation of lambda expressions.

当然,对于某些用例来说这是不幸的,但是在大多数实际应用中,并不需要真正的工具来检测lambda表达。例如,许多现实世界的仪器都应用于使用给定注释进行注释的方法,而这些方法不可能应用于lambda表达式或比功能接口更复杂的类。

This is of course unfortunate for some use cases, but in most real-life applications, there is no real requirement for instrumenting lambda expression. Many real-world instrumentations are for example applied to methods that are annotated with a given annotation what is not possible to apply to lambda expressions or to classes that are more complex than a functional interface.

更新:使用Byte Buddy版本1.1.0,可以检测表示lambda表达式的类。为此,Byte Buddy使用了JVM的 LambdaMetafactory 并将类生成替换为自定义。要激活此功能,请在构建器中执行以下步骤:

UPDATE: With Byte Buddy version 1.1.0, it is possible to instrument classes that represent lambda expressions. For this, Byte Buddy instruments the JVM's LambdaMetafactory and replaces the class generation with a custom definition. To activate this feature, execute the following step in the builder:

new AgentBuilder.Default()
  .with(LambdaInstrumentationStrategy.ENABLED)

请注意,这仅适用于OpenJDK 8u40,在以前的版本中,与invokedynamic呼叫网站相关的错误,导致该功能无法正常工作。

Note that this does only work with OpenJDK 8u40, in previous versions, there is a bug related to invokedynamic call sites that prevents this from working.

这篇关于使用Byte Buddy拦截对Java 8 lambda表达式的调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆