我希望为我的应用创建一个自定义远程执行客户端。客户可能看起来像这样:
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,看看是否可行。鉴于我之前从未进行过字节代码操作,我只想检查一下我说的是对的:
鉴于lambda就像一个匿名的内部类,我猜我也必须在那里重命名某种方法......
这大概是正确的还是我完全错了?
答案 0 :(得分:0)
请注意,lambda可以从其上下文中访问所有不可变值。因此,您需要禁止访问外部值(这会严重限制解决方案的有用性)或识别它们并发送这些值的表示(这会遇到您提到的问题;它们的实现可能在服务器类路径之外)
因此,即使您发送方法表示(您甚至不需要ASM;您可以直接从类加载器获取资源),它也不适用于一般情况。
编辑:鉴于您的评论,它可以工作。你需要用
来合成一个类答案 1 :(得分:0)
分析运行时生成的lambda表达式类没有意义。它们具有非常简单的结构,在序列化时会显示出来。在序列化期间,它们将被SerializedLambda
实例取代,该实例包含您可能收集的所有信息,最值得注意的是:
关键是目标方法。对于lambda表达式(与方法引用不同),目标方法是一种合成方法,它位于包含lambda表达式的类中。顺便说一句,该方法是private
,这就是为什么尝试复制调用该方法的类注定要失败的原因,需要特殊的JVM交互才能创建这样的类。但重要的是,您需要远程端的目标方法来执行它,lambda特定的运行时类是无关紧要的。如果您有目标方法,可以create the lambda instance without third party libraries。
当然,您可以使用ASM分析目标方法的代码以将其(以及所有依赖项)传输到远程端,但请注意,这与传输任意Function
实现没有区别;事实上,通过lambda表达式创建了一层运行时生成的类,这对你没有任何帮助。