我在Google App Engine上有一个使用DataNucleus / JDO的应用程序,我试图创建一个持久化对象池,这样用户请求就可以简单地获取一个键而不是等待一个新对象被持久化。
对象池保存在ArrayBlockingQueue< Key>中,每次用户请求新的Key I从队列中弹出一个并生成DeferredTask以持久保存新对象并将其添加到单独线程中的队列中,所以Key可以快速返回给用户:
@PersistenceCapable
public class EquipmentStock implements Serializable {
...
@Persistent(serialized="true")
private ArrayBlockingQueue<Key> blockingQueue;
public Key getEquipmentKey() throws IllegalArgumentException, InterruptedException {
Key key = blockingQueue.take();
QueueFactory.getDefaultQueue().add(withDefaults().payload(new DeferredTask() {
@Override
public void run() {
PersistenceManager pm = PMF.getInstance().getPersistenceManager();
try {
EquipmentItemData equipmentData = ObjectFetcher.fetchObjectByID(pm, EquipmentItemData.class, equipmentID, true);
EquipmentItem equipmentItem = new EquipmentItem(equipmentData);
pm.makePersistent(equipmentItem);
blockingQueue.put(equipmentItem.getKey());
}
...
}
}));
return key;
}
}
当应用程序关闭/重新启动时,我需要保存/加载队列的内容。 GAE不支持持久化ArrayBlockingQueues,因此我尝试将队列作为序列化对象持久化,但无法使用ClassCastException加载:
Failed startup of context com.google.apphosting.utils.jetty.RuntimeAppEngineWebAppContext@12b17d0{...}
java.lang.ClassCastException: org.datanucleus.store.types.sco.simple.Collection cannot be cast to java.util.concurrent.ArrayBlockingQueue
at {...}.EquipmentStock.jdoReplaceField(EquipmentStock.java)
at org.datanucleus.state.AbstractStateManager.replaceField(AbstractStateManager.java:2387)
at org.datanucleus.state.JDOStateManager.replaceField(JDOStateManager.java:1877)
at org.datanucleus.state.JDOStateManager.replaceField(JDOStateManager.java:1781)
at org.datanucleus.store.types.sco.SCOUtils.createSCOWrapper(SCOUtils.java:241)
at org.datanucleus.store.types.sco.SCOUtils.newSCOInstance(SCOUtils.java:139)
at org.datanucleus.state.JDOStateManager.wrapSCOField(JDOStateManager.java:2230)
at org.datanucleus.state.JDOStateManager.replaceAllLoadedSCOFieldsWithWrappers(JDOStateManager.java:2115)
at com.google.appengine.datanucleus.DatastorePersistenceHandler.insertObjectsInternal(DatastorePersistenceHandler.java:372)
at com.google.appengine.datanucleus.DatastorePersistenceHandler.insertObject(DatastorePersistenceHandler.java:218)
at org.datanucleus.state.JDOStateManager.internalMakePersistent(JDOStateManager.java:2381)
at org.datanucleus.state.JDOStateManager.makePersistent(JDOStateManager.java:2357)
at org.datanucleus.ObjectManagerImpl.persistObjectInternal(ObjectManagerImpl.java:1896)
at org.datanucleus.ObjectManagerImpl.persistObjectWork(ObjectManagerImpl.java:1745)
at org.datanucleus.ObjectManagerImpl.persistObject(ObjectManagerImpl.java:1602)
at org.datanucleus.api.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:731)
at org.datanucleus.api.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceManager.java:756)
at {...}.EquipmentStockLocator.initStock(EquipmentStockLocator.java:57)
at {...}.BootstrapListener.contextInitialized(BootstrapListener.java:13)
at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:548)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:219)
at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:194)
at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:134)
at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:446)
at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:437)
at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:444)
at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:188)
at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:308)
at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:300)
at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:441)
at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:251)
at java.lang.Thread.run(Thread.java:724)
据我所知,DataNucleus正在将ArrayBlockingQueue转换为其通用Collection类,但是在应用程序重新启动时无法将其强制转换,可能是因为转换为Collection丢弃了ArrayBlockingQueue的固定大小数据。
我不明白为什么它首先会抛出ArrayBlockingQueue,因为我指定它应该存储为单个序列化的blob。