解决dubbo中hessian序列化时Hibernate的延迟加载,以及Set,Map,List集合的解决方案

一、问题:
hibernate的延迟加载,导致序列化的时候会抛出Hibernate的LazyInitializationException.
还有就是hibernate的Map、List等会被转换为PersistentCollection对象,一般序列化框架没有针对此类的序列化方案。

二、主要应用场景
1、hibernate对象在缓存的时候,进行序列化操作
2、hibernate对象在使用hessian的RPC操作的时候进行序列化。
3、hibernate对象在进行json对象转换的时候。

三、一班的解决方案
使用DTO/VO对象对hibernate对象进行转换,但是缺点也很明显,代码冗余非常大,DTO/VO对象泛滥。

三、现象以及二班的解决方法
1、对于场景1的解决方案(hibernate对象的缓存)
1)将需要延迟加载的对象,都改成非延迟加载。这个其实也很正常,既然需要缓存对象,又何必延迟加载呢?所以这种方案无可厚非。

2、对于场景2的解决方案(RPC的序列化)
RPC的序列化跟转换成json有个最大的不同点,就是此序列化不会调用get方法获取值,就是IO操作,所以3的方案不可用。

本人是在dubbo中用hessian进行序列化的时候碰到的问题,所以就针对此框架来说吧。
其实在上面的问题中已经描述,就是PersistentCollection对象无法识别,那么就增加对此序列化的方法呗。

public class HibernateSerializerFactory extends SerializerFactory {

    private HibernateListSerializer listSerializer = new HibernateListSerializer();
    private HibernateMapSerializer mapSerializer = new HibernateMapSerializer();
    private HibernateBeanSerializer hibernateBeanSerializer = new HibernateBeanSerializer();

    @SuppressWarnings("rawtypes")
    public Serializer getSerializer(Class cl) throws HessianProtocolException {
        if (PersistentMap.class.isAssignableFrom(cl)) {
            return mapSerializer;
        } else if (AbstractPersistentCollection.class.isAssignableFrom(cl)) {
            return listSerializer;
        } else if (cl.getSimpleName().contains("_$$_javassist_")) {
            return hibernateBeanSerializer;
        }
        return super.getSerializer(cl);
    }

    private static class HibernateBeanSerializer implements Serializer {
        @Override
        public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
            boolean init = Hibernate.isInitialized(obj);

            out.writeObject(init ? obj : null);
            out.flush();
            return;
        }
    }

    private static class HibernateListSerializer implements Serializer {
        private CollectionSerializer delegate = new CollectionSerializer();

        @SuppressWarnings({"unchecked", "rawtypes"})
        public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
            if (Hibernate.isInitialized(obj)) {
                delegate.writeObject(new ArrayList((Collection) obj), out);
            } else {
                delegate.writeObject(new ArrayList(), out);
            }
        }

    }

    private static class HibernateMapSerializer implements Serializer {
        private MapSerializer delegate = new MapSerializer();

        @SuppressWarnings({"unchecked", "rawtypes"})
        public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
            if (Hibernate.isInitialized(obj)) {
                delegate.writeObject(new HashMap((Map) obj), out);
            } else {
                delegate.writeObject(new HashMap(), out);
            }
        }

    }
}


dubbo中通过添加配置文件,可以增加自己的序列化工厂。






3、对于场景3的现象与方案(hibernate进行json对象转换)
1) Hibernate碰到延迟加载的属性访问时如果session被关闭则抛出LazyInitializationException
2) Hibernate中的one-to-many等关联关系在序列化时如果没有控制,则将整个 数据库都有可能被全部序列化
3) 过多的使用DTO/ValueObject解决这个问题。

解决办法:

1、可以使用阿里巴巴的fastjson,对这种一对多或多对一的对象序列化做到了可控性,通过在序列化的时候添加SerializerFeature中的DisableCircularReferenceDetect即可。至于延迟加载可以用OpenSessionInView,这个也只局限于web才可以。

2、对Entity对象生成一个动态代理,拦截getXXXX()方法,如果访问的是延迟加载的属性,则return null,而不抛出LazyInitializationException,递归生成属性的代理,只要碰到未延迟加载的属性,而序列化会自动停止.避免将整个Entity序 列化传播,导致可能序列化整个数据库的问题。

猜你喜欢

转载自wzalong.iteye.com/blog/2323787