MSM Session共享实现时 Hibernate持久化对象的Kryo序列化方案。
在用MSM 来共享集群中HttpSession的场景中
如果Session中有Hibernate的持久化对象(通过list()等获得的对象)。在利用Kryo做序列化时会有很多问题。
在看了MSM和Kryo的一部分源码后,得到以下解决方案:
在Context-Manager 标签中配置以下属性:
customConverter="xx.xxKryoRegistration"
<Context docBase="xx" path="/xx" crossContext="true" debug="3" privileged="true" reloadable="true">
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:xxxxxxxx:11211" requestUriIgnorePattern=".*\.(png|gif|jpg|css|js)$"
sticky="false"
lockingMode="auto"
sessionBackupAsync="false"
sessionBackupTimeout="60000"
memcachedProtocol="binary"
copyCollectionsForSerialization="true"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
customConverter="xx.xxKryoRegistration" />
</Context>
这个时候因为xx.xxKryoRegistration中需要关联项目中的Hibernate包。所以context配置需要放在当前项目中。或者用其它延迟加载的办法。不然会报找不到类。
创建类xx.xxKryoRegistration 并打成jar包;
代码如下:
package xx; import org.hibernate.proxy.HibernateProxy; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.Serializer; import de.javakaffee.web.msm.serializer.kryo.KryoCustomization; import de.javakaffee.web.msm.serializer.kryo.SerializerFactory; public class xxKryoRegistration implements KryoCustomization, SerializerFactory { private Kryo kryo; public xxKryoRegistration (Kryo kryo) { this.kryo = kryo; } @Override public void customize(Kryo kryo) { } @Override public Serializer newSerializer(Class<?> type) { if (HibernateProxy.class.isAssignableFrom(type)) { return new HibernateProxySerializer(kryo); } return null; } }
HibernateProxySerializer 代码如下:
package xx; import java.nio.ByteBuffer; import org.hibernate.Hibernate; import org.hibernate.proxy.HibernateProxy; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.Serializer; import com.esotericsoftware.kryo.serialize.FieldSerializer; public class HibernateProxySerializer extends Serializer { private Kryo kryo; public HibernateProxySerializer(Kryo kryo) { this.kryo = kryo; } @SuppressWarnings("unchecked") @Override public void writeObjectData(ByteBuffer buffer, Object object) { //处理空: if (object == null) { buffer.put((byte) 0); } Object serialObj = object; Class<? extends Object> realType = object.getClass(); //判断是否是Hibernate的代理类 if (object instanceof HibernateProxy) { //取真实类型 realType = ((HibernateProxy) object).getHibernateLazyInitializer() .getPersistentClass(); //判断是否已加载,如果未加载,直接创建空对象,或者直接写空值(buffer.put((byte)0)) if (!Hibernate.isInitialized(object)) { try { serialObj = ((HibernateProxy) object) .getHibernateLazyInitializer().getPersistentClass() .newInstance(); } catch (Exception e) { serialObj = null; } } else { //否则直接取加载好的真实类型的对象 serialObj = ((HibernateProxy) object) .getHibernateLazyInitializer().getImplementation(); } } new FieldSerializer(kryo, realType).writeObject(buffer, serialObj); } @SuppressWarnings("unchecked") @Override public <T> T readObjectData(ByteBuffer buffer, Class<T> type) { Class<? extends Object> realType = type; //取真实类型 if (HibernateProxy.class.isAssignableFrom(type)) { realType = type.getSuperclass(); } //按照真实类型解析对象 return (T) new FieldSerializer(kryo, realType).readObject(buffer, realType); } }
然后发现不行额。
继续寻找中。