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序 列化传播,导致可能序列化整个数据库的问题。