ASM可以实现远程执行客户端吗?

时间:2015-03-17 11:45:58

标签: java lambda java-bytecode-asm

我希望为我的应用创建一个自定义远程执行客户端。客户可能看起来像这样:

interface Client {

    <T> T computeRemotely(Function<List<MyBigObject>, T> consumer)
}

可能会像这样使用:

Client client = new Client();
Integer remoteResult = client.computeRemotely(list -> {
    Integer result = -1;

    // do some computational work here.

    return result;
});

这意味着我需要从客户端获取lambda,将其发送到服务器,运行该函数(传入真实List<MyBigObject>)并将结果发回。

值得注意的是,使用我的客户端库的限制是你不能在该lambda中使用JDK以外的任何东西并期望它能够工作(因为类可能不在服务器上的类路径上)。 ..但我希望他们能够使用任何JDK类将自己的数据引入计算中。

现在我不能序列化Function<MyBigObject, T> lambda,因为它序列化为lambda存在的任何类的内部客户端,而不存在于服务器上的类路径中。

所以我一直在寻找ASM,看看是否可行。鉴于我之前从未进行过字节代码操作,我只想检查一下我说的是对的:

  • 我可以使用ASM转换为读取lambda所在的类。
  • 使用方法访问者,获取方法字节,将它们发送到服务器
  • 使用ASM从字节创建实例并执行它。

鉴于lambda就像一个匿名的内部类,我猜我也必须在那里重命名某种方法......

这大概是正确的还是我完全错了?

2 个答案:

答案 0 :(得分:0)

请注意,lambda可以从其上下文中访问所有不可变值。因此,您需要禁止访问外部值(这会严重限制解决方案的有用性)或识别它们并发送这些值的表示(这会遇到您提到的问题;它们的实现可能在服务器类路径之外)

因此,即使您发送方法表示(您甚至不需要ASM;您可以直接从类加载器获取资源),它也不适用于一般情况。

编辑:鉴于您的评论,它可以工作。你需要用

来合成一个类
  • 上下文属性为最终字段
  • 包含所有字段参数的构造函数(您将在构造时传递反序列化的值)
  • lambda方法 - 请参阅this question for details

答案 1 :(得分:0)

分析运行时生成的lambda表达式类没有意义。它们具有非常简单的结构,在序列化时会显示出来。在序列化期间,它们将被SerializedLambda实例取代,该实例包含您可能收集的所有信息,最值得注意的是:

关键是目标方法。对于lambda表达式(与方法引用不同),目标方法是一种合成方法,它位于包含lambda表达式的类中。顺便说一句,该方法是private,这就是为什么尝试复制调用该方法的类注定要失败的原因,需要特殊的JVM交互才能创建这样的类。但重要的是,您需要远程端的目标方法来执行它,lambda特定的运行时类是无关紧要的。如果您有目标方法,可以create the lambda instance without third party libraries

当然,您可以使用ASM分析目标方法的代码以将其(以及所有依赖项)传输到远程端,但请注意,这与传输任意Function实现没有区别;事实上,通过lambda表达式创建了一层运行时生成的类,这对你没有任何帮助。