java序列化时如何遍历复杂对象嵌套的所有对象

        先说开发环境,我们是OSGI环境,使用的是struts2自带的OSGI插件的环境(当然了,我们对该插件做了升级,Struts2自带的插件支持felix版本比较低)。在解决项目问题时需要对系统中的一些对象进行序列化和反序列化,而要序列化的对象是放在OSGI环境中的bundle中,但是我们的序列化工具因为某种原因必须放在war包的lib下,而ObjectInputStream类在反序列化的时候不但需要知道当时被序列化的最外层类的class信息,而且需要知道这个外层类递归嵌套的所有类的class信息。而OSGI环境中的bundle中的类的的类加载器和lib下的类的类加载器不是同一个,也就是说在ObjectInputStream中是无法访问序列化的类的class信息的,而经过查看ObjectInputStream的源码发现其反序列化前调用的是resolveClass来加载这类的,代码如:

    protected Class resolveClass(ObjectStreamClass desc)
        throws IOException, ClassNotFoundException
    {
        String name = desc.getName();
        try {
            return Class.forName(name, false, latestUserDefinedLoader());
        } catch (ClassNotFoundException ex) {
            Class cl = primClasses.get(name);
            if (cl != null) {
                return cl;
            } else {
                throw ex;
            }
        }
    }

       从代码可以看出是类加载器不对的问题,那么怎么解决这个问题呢?因为我们在序列化的时候是能拿到要序列化的对象的,那么在那个时候只要我们获取到类的class信息并且缓存成Map,最后通过class的name就可以拿到,问题是反序列化的时候要递归遍历获取外层类嵌套的所有类的class信息,怎么办呢?经过阅读ObjectOutputStream类,发现这个类中大部分方法都是private的,这很显然是不能扩展了,后来看到replaceObject方法,发现在序列化的时候递归序列化最外层类的所有递归嵌套类都要调用一遍这方法,太好了。于是扩展了这个ObjectOutputStream的replaceObject方法,在这里把所有class信息缓存即可,代码如下:

@Override
protected Object replaceObject(Object obj) throws IOException {
String key = obj.getClass().getName();
Class clazz = SessionClassCache.getClass(key);
if(null == clazz) {
SessionClassCache.putClass(obj.getClass());// SessionClassCache是我定义的一个缓存,其实就是个Map>
}
return super.replaceObject(obj);
}

      上边ObjectInputStream的resolveClass方法扩展代码如:

       @Override
protected Class resolveClass(ObjectStreamClass desc) throws IOException{
Class clazz = null;
try {
clazz = super.resolveClass(desc);
} catch (ClassNotFoundException e) {
clazz = SessionClassCache.getClass(desc.getName());
}

return clazz;
}

       以上就是解决思路,阅读源码很有益处啊!之前网上找不到这种资料,所以写了下给各位网友提供个思路。


你可能感兴趣的:(架构设计)