在 Weblogic 12c 中反序列化时发生 ClassNotFoundException

ClassNotFoundException while deserializing in Weblogic 12c

我有一个在客户端保存状态的网络应用程序。状态被累积成一个 Object []

Object state[] = new Object[10];

state[0] = _parent_s_state_array
state[1] = _some_int;
state[2] = _some_POJO;
..
..

那就是

在下一个请求中,这个序列化状态被提交回来,我们逆向步骤在服务器端重建状态。此策略适用于数百页。

但是对于使用具有少量 String 属性的特定 POJO 的特定页面,我在反序列化时得到 ClassNotFoundException。需要注意的是,同一 class 的对象是在同一 JVM 会话中创建和序列化的,因此我们可以排除 Class 不存在于 class 路径中。

更多观察

有人可以提供一些 pointers/strategy 来 war 调试这个问题。

提前致谢。

异常

ERROR [[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'] ClassNotFoundException occured restoring StateManager state from serialized form
java.lang.ClassNotFoundException: com.xxx.yyy.TimeParameters
        at java.net.URLClassLoader.run(URLClassLoader.java:366) ~[na:1.7.0_65]
        at java.net.URLClassLoader.run(URLClassLoader.java:355) ~[na:1.7.0_65]
        at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_65]
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354) ~[na:1.7.0_65]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:425) ~[na:1.7.0_65]
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) ~[na:1.7.0_65]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ~[na:1.7.0_65]
        at java.lang.Class.forName0(Native Method) [na:1.7.0_65]
        at java.lang.Class.forName(Class.java:270) [na:1.7.0_65]
        at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:625) ~[na:1.7.0_65]
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1612) ~[na:1.7.0_65]
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517) ~[na:1.7.0_65]
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771) ~[na:1.7.0_65]
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370) ~[na:1.7.0_65]
        at org.apache.commons.collections.map.AbstractHashedMap.doReadObject(AbstractHashedMap.java:1212) ~[weblogic.server.merged.jar:12.1.3.0.0]
        at org.apache.commons.collections.map.CaseInsensitiveMap.readObject(CaseInsensitiveMap.java:149) ~[weblogic.server.merged.jar:12.1.3.0.0]

Class

package com.xxx.yyy;
public class TimeParameters implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 5384703411813811209L;
    private String yr;
    private String qtr;
    private String mth;
    private String analysisType;

// Getters and Setters
...
...
}

Java 序列化不是完成任务的最佳方式。您最好将其序列化为(例如)JSON,然后根据需要对其进行压缩。 google GSON 是不错的选择。或者 XStream 与 JSON 驱动程序。或者杰克逊...

TLDR;

来自 Apache Commons 集合的 class 在序列化过程中的某个地方被涉及。由于 apache-commons-collections 是从 Weblogic jar 加载的,因此在 Application classloader 中搜索 required class 找不到它。修复是将 org.apache.commons.collections.* 添加到 weblogic.xml

中的 prefer-application-packages

详情

我做了一个远程调试器会话来跟踪对 Class.forName0(String className, boolean, ClassLoader loader) 的调用。

发现当需要的class可以加载时,通过的class加载器层次更深

this contains all classes in WEB-INF/classes --> weblogic.utils.classloaders.ChangeAwareClassLoader@6437e3af finder: weblogic.utils.classloaders.CodeGenClassFinder@2cd01c0c annotation: mi.8200@MedicalIntelligence 
weblogic.utils.classloaders.FilteringClassLoader@6413df9c finder: weblogic.utils.classloaders.CodeGenClassFinder@54bdae18 annotation: 
weblogic.utils.classloaders.GenericClassLoader@5919d25d finder: weblogic.utils.classloaders.CodeGenClassFinder@1265cb83 annotation: 
java.net.URLClassLoader@5a88cbff
Application classloader, contains classes from weblogic bundled jars -->  sun.misc.Launcher$AppClassLoader@2a9a42ef 
sun.misc.Launcher$ExtClassLoader@75a06ec2

当它抛出 ClassNotFoundException 时,它被缩短了——只出现了最后两个条目

sun.misc.Launcher$AppClassLoader@2a9a42ef <--   Hierarchy starts at Application classloader
sun.misc.Launcher$ExtClassLoader@75a06ec2

然后,我注意到堆栈跟踪包含这些以 ~[weblogic.server.merged.jar:12.1.3.0.0] 结尾的行(编辑问题以添加更多堆栈跟踪)

    at org.apache.commons.collections.map.AbstractHashedMap.doReadObject(AbstractHashedMap.java:1212) ~[weblogic.server.merged.jar:12.1.3.0.0]
    at org.apache.commons.collections.map.CaseInsensitiveMap.readObject(CaseInsensitiveMap.java:149) ~[weblogic.server.merged.jar:12.1.3.0.0]

所以 Apache commons 集合是从 weblogic 捆绑的 jar 中加载的,即 sun.misc.Launcher$AppClassLoader@2a9a42ef 这可能会触发 错误 classloader 进一步向下传递.所以在 weblogic.xml

中将 org.apache.commons.collections.* 添加到 prefer-application-packages
    <prefer-application-packages> 
        ...
        <package-name>org.apache.commons.collections.*</package-name>
    </prefer-application-packages> 

有用的资源