【发布时间】:2019-08-22 18:12:46
【问题描述】:
我在玩基本的 infinispan 集群,遇到了一个令人费解的错误。
我基本上是在实现一个共享地图,只保存一个整数
这是我的服务代码
package sandbox.infinispan.test.service;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.infinispan.Cache;
@Named("useThisOne")
@ApplicationScoped
public class CounterService implements ICounterService {
private static final String KEY = "key";
@Inject
private Cache<String, Integer> cache;
@Override
public void inc(final int amount) {
this.cache.put(KEY, Integer.valueOf(this.get() + amount));
}
@Override
public int get() {
return this.cache.computeIfAbsent(KEY, k -> Integer.valueOf(0)).intValue();
}
}
缓存由以下内容产生:
package sandbox.infinispan.test.config;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfiguration;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
@Dependent
class CacheProvider {
@Produces
@ApplicationScoped
private EmbeddedCacheManager defaultClusteredCacheManager() {
final GlobalConfiguration g = new GlobalConfigurationBuilder() //
.clusteredDefault() //
.transport() //
.nodeName(this.getNodeName()) //
.clusterName("infinispanTestCluster") //
.build();
final Configuration cfg = new ConfigurationBuilder() //
.clustering() //
.cacheMode(CacheMode.REPL_SYNC) ///
.build();
return new DefaultCacheManager(g, cfg);
}
}
当集群中至少有两台服务器时,computeIfAbsent 失败并显示
15:48:50,253 ERROR [org.infinispan.interceptors.impl.InvocationContextInterceptor] (jgroups-7,myhostname-14393) ISPN000136: Error executing command ComputeIfAbsentCommand, writing keys [key]: org.infinispan.remoting.RemoteException: ISPN000217: Received exception from otherhostname-44445, see cause for remote stack trace
深入到:
Caused by: java.lang.NoSuchMethodException: sandbox.infinispan.test.service.CounterService.$deserializeLambda$(java.lang.invoke.SerializedLambda)
最后是:
Caused by: java.lang.IllegalArgumentException: Invalid lambda deserialization
at sandbox.infinispan.test.service.CounterService.$deserializeLambda$(CounterService.java:10)
... 68 more
Caused by: an exception which occurred:
in object of type java.lang.invoke.SerializedLambda
如果我将我漂亮的时尚代码重写为丑陋的追随者,它会起作用。
@Override
public int get() {
Integer value = this.cache.get(KEY);
if (value == null) {
value = Integer.valueOf(0);
this.cache.put(KEY, value);
}
return value.intValue();
}
我现在如何使用漂亮的 computeIfAbsent 做事方式?
Eclipse 2018-12,WildFly 14,java 10 on 集群的 dev 成员,CentOs 7,OpenJdk 10,WildFly 14 在远程集群成员上。
感谢您的帮助
解决了(有点)
感谢我在这里得到的帮助,我将 lambda 转换为一个内部类:
static class OhWell implements Serializable {
static Integer zero(final String t) {
return Integer.valueOf(0);
}
}
@Override
public int get() {
return this.cache.computeIfAbsent(KEY, OhWell::zero).intValue();
}
它现在可以工作了,但它不如整洁的 lambda 好。所以我会坚持老式的方法——除非有人能想到更好的方法。
进一步的结果:
以下带有 static 方法的 static 内部类可以工作
static class StaticOhWell implements Serializable {
static Integer apply(final String t) {
return Integer.valueOf(0);
}
}
@Override
public int get() {
return this.cache.computeIfAbsent(KEY, StaticOhWell::apply).intValue();
}
以下具有非静态方法的非静态内部类失败:
class NotStaticOhWell implements SerializableFunction<String, Integer> {
@Override
public Integer apply(final String t) {
return Integer.valueOf(0);
}
}
@Override
public int get() {
return this.cache.computeIfAbsent(KEY, new NotStaticOhWell()::apply).intValue();
}
失败并显示此错误消息 NotSerializableException: org.infinispan.cache.impl.EncoderCache:
13:41:29,221 ERROR [org.infinispan.interceptors.impl.InvocationContextInterceptor] (default task-1) ISPN000136: Error executing command ComputeIfAbsentCommand, writing keys [value]: org.infinispan.commons.marshall.NotSerializableException: org.infinispan.cache.impl.EncoderCache
Caused by: an exception which occurred:
in field sandbox.infinispan.test.service.CounterService.cache
in object sandbox.infinispan.test.service.CounterService@4612a6c3
in field sandbox.infinispan.test.service.CounterService$NotStaticOhWell.this$0
in object sandbox.infinispan.test.service.CounterService$NotStaticOhWell@4effd362
in field java.lang.invoke.SerializedLambda.capturedArgs
in object java.lang.invoke.SerializedLambda@e62f08a
in object sandbox.infinispan.test.service.CounterService$$Lambda$1195/1060417313@174a143b
结束语 (?)
使用“静态 lambda”(实现 SerializableFunction 接口的 static 内部类)也很有效
static class StaticSerializableFunction implements SerializableFunction<String, Integer> {
@Override
public Integer apply(final String t) {
return Integer.valueOf(0);
}
}
@Override
public int get() {
return this.cache.computeIfAbsent(KEY, new StaticSerializableFunction()::apply).intValue();
}
获胜者是……
通过“transienting”使类真正可序列化,Cache 允许简单地使用此类的方法。无需创建内部类!
package sandbox.infinispan.test.service;
import java.io.Serializable;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.infinispan.Cache;
@Named("useThisOne")
@ApplicationScoped
public class CounterService implements ICounterService, Serializable {
private static final String KEY = "value";
@SuppressWarnings("cdi-ambiguous-dependency")
@Inject
private transient Cache<String, Integer> cache;
@Override
public void inc(final int amount) {
this.cache.put(KEY, Integer.valueOf(this.get() + amount));
}
@Override
public int get() {
return this.cache.computeIfAbsent(KEY, this::zero).intValue();
}
private Integer zero(@SuppressWarnings("unused") final String unused) {
return Integer.valueOf(0);
}
@Override
public void reset() {
this.cache.clear();
}
}
谢谢大家!
【问题讨论】:
-
远程节点上是否存在
CounterService类?您是否尝试过将 lambda 更改为匿名内部类? -
@DanBerindei 谢谢,将 lambda 移动到内部类(虽然不是匿名)成功了。
-
恐怕您只是将实现移动到嵌套类中,
OhWell::zero仍然是一个 lambda。但是因为它只引用嵌套类中的静态方法,所以它不会捕获任何东西,而且它肯定是可序列化的。 -
重新阅读描述,我现在很确定
Caused by: java.lang.NoSuchMethodException: sandbox.infinispan.test.service.CounterService.$deserializeLambda$(java.lang.invoke.SerializedLambda)表示部署在远程节点上的CounterService类是在您添加 lambda 之前编译的,如果您添加 lambda,您的初始 lambda 将起作用在所有节点上部署相同的CounterService类。 -
@DanBerindei 不。我非常确定在 Wildfly(苍蝇?)中运行完全相同的代码,并且仍然无效 lambda 反序列化
标签: wildfly infinispan jgroups