我们正在将Jetty从9.3.x升级到9.4.x,并遇到会话集群问题。
当服务器尝试加载会话时,它将尝试解组存储在会话属性中的对象。它无法加载这些对象的相关类。 SessionManager的类加载器似乎无法访问已部署的WAR本身中的类路径。
我们使用单独的码头基地部署到码头。我们的WebAppContext看起来像这样:
<Configure id="support-server" class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/</Set>
<Set name="war"><Property name="jetty.base" default="."/>/support-server.war</Set>
<Set name="extraClasspath"><Property name="jetty.base" default="."/>/config</Set>
<Set name="defaultsDescriptor"><Property name="jetty.base" default="."/>/etc/webdefault.xml</Set>
<Set name="tempDirectory">tmp</Set>
<Set name="maxFormKeys">10000</Set>
<Set name="maxFormContentSize">2000000</Set>
</Configure>
使用jetty-home工程中的start.jar部署和启动Webapp。该应用程序可以按需使用。但是,当我们重新启动服务器并从存储中加载会话时,它将引发Un可读SessionDataException。
我们尝试了基于Google Cloud Datastore和MongoDB的会话存储,但最终都遇到了同样的问题。查看github(https://github.com/eclipse/jetty.project/blob/jetty-9.4.14.v20181114/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java)上的代码,可以发现所使用的机制相同:
try (ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(blob.asInputStream()))
{
SessionData.deserializeAttributes(session, ois);
}
catch (Exception e)
{
throw new UnreadableSessionDataException (id, _context, e);
}
堆栈跟踪的详细信息是:
Caused by:
org.eclipse.jetty.server.session.UnreadableSessionDataException:
Unreadable session developmentsplje48spmp5vzaujq3ydjga0 for development__0.0.0.0
at org.eclipse.jetty.gcloud.session.GCloudSessionDataStore.sessionFromEntity(GCloudSessionDataStore.java:944)
at org.eclipse.jetty.gcloud.session.GCloudSessionDataStore.doLoad(GCloudSessionDataStore.java:509)
... 30 more
Caused by: java.lang.ClassNotFoundException:
com.fleetnology.support.web.overview.mo.TicketOverviewTableMo
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:683)
at org.eclipse.jetty.util.ClassLoadingObjectInputStream.resolveClass(ClassLoadingObjectInputStream.java:93)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1863)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1746)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2037)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:428)
at java.util.HashMap.readObject(HashMap.java:1409)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1158)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2173)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2064)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:428)
at org.eclipse.jetty.util.ClassLoadingObjectInputStream.readObject(ClassLoadingObjectInputStream.java:70)
at org.eclipse.jetty.server.session.SessionData.deserializeAttributes(SessionData.java:126)
at org.eclipse.jetty.gcloud.session.GCloudSessionDataStore.sessionFromEntity(GCloudSessionDataStore.java:940)
... 31 more
9.3.X中SessionManager的实现未使用ClassLoadingObjectInputStream,也没有引起任何问题。
这里的大多数问题和解决方案都与逆相关,WAR中的类无法使用Jetty Server类。
关于Jetty中的ClassLoading的文档似乎集中在从Web应用程序到Jetty Server的类的访问权限上。