使用动态代理解决Hibernate序列化,避免延迟加载问题

在使用Ajax: Hibernate Entity => json, Flex RemoteObject: Hibernate Entity => ActionScript. Object的过程,经常碰到如下问题:

问题:

1.Hibernate碰到延迟加载的属性访问时如果session被关闭则抛出 LazyInitializationException

2.Hibernate中的one-to-many等关联关系在序列化时如果没有控制,则将整个 数据库都有可能被全部序列化

3.过多的使用DTO/ValueObject解决这个问题.

解决办法:

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

类似解决方案:

dwr中HibernateConverter,在序列化时如上类似,碰到延迟加载的属性自动停 止convert工作.而HibernateBeanSerializer则一劳永逸,无论object => json都可以工作.

使用用例:

Java代码

//role为原始对象role = (Role)roleDao.getById( new Long( 1 ));//生成的动态代理proxyRole,访问延迟加载的属性将return nullRole proxyRole = (Role) new  HibernateBeanSerializer(role).getProxy ();assertNotNull(role.getResource());assertNull (proxyRole.getResource()); //延迟加载,为nullHibernate.initialize (role.getResource()); //抓取进来  assertNotNull (proxyRole.getResource()); //不为null//role为原始对象role = (Role)roleDao.getById(new Long(1));//生成的动态代理proxyRole,访问 延迟加载的属性将return nullRole proxyRole = (Role)new HibernateBeanSerializer(role).getProxy ();assertNotNull(role.getResource());assertNull (proxyRole.getResource()); //延迟加载,为nullHibernate.initialize (role.getResource()); //抓取进来assertNotNull (proxyRole.getResource()); //不为null

源码.

Java代码

package cn.org.rapid_framework.util;import  java.lang.reflect.Modifier;import java.util.ArrayList;import  java.util.Collection;import java.util.LinkedHashMap;import  java.util.LinkedHashSet;import java.util.List;import  java.util.Map;import java.util.Set;import  org.aopalliance.intercept.MethodIntercepTor;import  org.aopalliance.intercept.MethodInvocation;import  org.hibernate.Hibernate;import  org.hibernate.collection.PersistentCollection;import  org.hibernate.proxy.HibernateProxy;import  org.springframework.aop.framework.ProxyFacTory;import  org.springframework.util.StringUtils;/** * 用于Hibernate Object 的序列化,访问延迟加载的属性不会抛出LazyInitializationException, 而会返回null值. * 使用: *

<br />* Blog proxyBlog = new HibernateBeanSerializer(blog).getProxy();<br />* 

* @author badqiu * @param */  public  class  HibernateBeanSerializer {  T proxy = null ;   /**    */     public HibernateBeanSerializer(T object,String... excludesProperties) {     if (object == null ) {       this .proxy = null ;    } else {       ProxyFacTory pf = new ProxyFacTory();       pf.setTargetClass(object.getClass());      pf.setOptimize( true );      pf.setTarget(object);       pf.setProxyTargetClass( true );      pf.setOpaque( true );      pf.setExposeProxy( true );       pf.setPreFiltered( true );       HibernateBeanSerializerAdvice beanSerializerAdvice = new  HibernateBeanSerializerAdvice();       beanSerializerAdvice.setExcludesProperties(excludesProperties);       pf.addAdvice(beanSerializerAdvice);       this .proxy = (T)pf.getProxy();    }  }   public T getProxy(){     return  this .proxy;  }   static   private  class HibernateBeanSerializerAdvice implements  MethodIntercepTor {     private String[] excludesProperties =  new String[ 0 ];     public String[] getExcludesProperties() {       return  excludesProperties;    }     public  void  setExcludesProperties(String[] excludesProperties) {       this .excludesProperties = excludesProperties == null ? new  String[ 0 ] : excludesProperties;    }     public  Object invoke(MethodInvocation mi) throws Throwable {       String propertyName = getPropertyName(mi.getMethod().getName());      Class returnType = mi.getMethod().getReturnType();        if (propertyName == null ) {         return  mi.proceed();      }       if (! Hibernate.isPropertyInitialized(mi.getThis(), propertyName)) {          return  null ;      }       if (isExclude(mi, propertyName)) {         return  null ;      }      Object returnValue = mi.proceed ();       return processReturnValue(returnType, returnValue);    }     private Object processReturnValue(Class returnType, Object returnValue) {        if (returnValue == null )         return  null ;       if (returnType != null && Modifier.isFinal(returnType.getModifiers())) {         return returnValue;      }       //This might be a lazy-collection so we need to double check       if (! Hibernate.isInitialized(returnValue)) {         return  null ;      }       //this is Hibernate Object       if (returnValue instanceof HibernateProxy) {          return  new HibernateBeanSerializer (returnValue).getProxy();      } else  if (returnValue  instanceof PersistentCollection) {         if (returnType.isAssignableFrom(Map. class )) {           Map proxyMap = new LinkedHashMap();          Map map = (Map)returnValue;          Set entrySet = map.entrySet();           for (Map.Entry entry : entrySet) {            proxyMap.put(entry.getKey(),  new HibernateBeanSerializer(entry.getValue()));           }           return proxyMap;        }        Collection proxyCollection = null ;          if (returnType.isAssignableFrom(Set. class )) {           proxyCollection = new LinkedHashSet();        } else   if (returnType.isAssignableFrom(List. class )) {           proxyCollection = new ArrayList();        } else  {           return returnValue;        }          for (Object o : (Collection)returnValue) {           proxyCollection.add( new HibernateBeanSerializer (o).getProxy());        }         return  proxyCollection;      } else {         return  returnValue;      }    }     private  boolean isExclude(MethodInvocation mi, String propertyName)          throws Throwable {       for (String excludePropertyName : excludesProperties) {         if (propertyName.equals(excludePropertyName)) {           return  true ;        }      }       return  false ;    }     private  static String getPropertyName(String methodName) {      String propertyName = null ;       if (methodName.startsWith( "get" )) {        propertyName = methodName.substring( "get" .length());      } else  if (methodName.startsWith( "is" )) {        propertyName = methodName.substring( "is" .length());      } else  if (methodName.startsWith( "set" )) {        propertyName = methodName.substring( "set" .length());      }       return propertyName ==  null ? null : StringUtils.uncapitalize(propertyName);    }   }}package cn.org.rapid_framework.util;import java.lang.reflect.Modifier;import java.util.ArrayList;import java.util.Collection;import java.util.LinkedHashMap;import java.util.LinkedHashSet;import java.util.List;import java.util.Map;import java.util.Set;import org.aopalliance.intercept.MethodIntercepTor;import org.aopalliance.intercept.MethodInvocation;import org.hibernate.Hibernate;import org.hibernate.collection.PersistentCollection;import org.hibernate.proxy.HibernateProxy;import org.springframework.aop.framework.ProxyFacTory;import org.springframework.util.StringUtils;/*** 用于Hibernate Object 的序列化,访问延迟加载的属性不会抛出LazyInitializationException,而会返 回null值.* 使用:*

<br />* Blog proxyBlog = new HibernateBeanSerializer(blog).getProxy();<br />* 

* @author badqiu* @param */public class HibernateBeanSerializer {T proxy = null;/**  */public HibernateBeanSerializer(T object,String... excludesProperties) { if(object == null) { this.proxy = null; }else { ProxyFacTory pf = new ProxyFacTory();  pf.setTargetClass(object.getClass()); pf.setOptimize(true);  pf.setTarget(object); pf.setProxyTargetClass(true);  pf.setOpaque(true); pf.setExposeProxy(true);  pf.setPreFiltered(true); HibernateBeanSerializerAdvice beanSerializerAdvice = new HibernateBeanSerializerAdvice();  beanSerializerAdvice.setExcludesProperties(excludesProperties);  pf.addAdvice(beanSerializerAdvice); this.proxy = (T)pf.getProxy (); }}public T getProxy(){ return this.proxy;} static private class HibernateBeanSerializerAdvice implements MethodIntercepTor { private String[] excludesProperties = new String[0]; public String[] getExcludesProperties() { return excludesProperties; } public void setExcludesProperties (String[] excludesProperties) { this.excludesProperties = excludesProperties == null ? new String[0] : excludesProperties;  } public Object invoke(MethodInvocation mi) throws Throwable { String propertyName = getPropertyName(mi.getMethod().getName ()); Class returnType = mi.getMethod().getReturnType(); if (propertyName == null) {  return mi.proceed(); } if(! Hibernate.isPropertyInitialized(mi.getThis(), propertyName)) {   return null; } if(isExclude(mi, propertyName)) {   return null; } Object returnValue = mi.proceed();  return processReturnValue(returnType, returnValue); }  private Object processReturnValue(Class returnType, Object returnValue) { if(returnValue == null)  return null;  if(Modifier.isFinal(returnType.getModifiers())) {  return returnValue; } //This might be a lazy-collection so we need to double check if(!Hibernate.isInitialized(returnValue)) {   return null; } //this is Hibernate Object if (returnValue instanceof HibernateProxy) {  return new HibernateBeanSerializer(returnValue).getProxy(); }else if (returnValue instanceof PersistentCollection) {  if (returnType.isAssignableFrom(Map.class)) {  Map proxyMap = new LinkedHashMap();  Map map = (Map)returnValue;   Set entrySet = map.entrySet();  for(Map.Entry entry : entrySet) {   proxyMap.put(entry.getKey(), new HibernateBeanSerializer(entry.getValue()));  }  return proxyMap;  }  Collection proxyCollection = null;   if(returnType.isAssignableFrom(Set.class)) {  proxyCollection = new LinkedHashSet();  }else if(returnType.isAssignableFrom (List.class)) {  proxyCollection = new ArrayList();  }else {  return returnValue;  }  for(Object o : (Collection)returnValue) {  proxyCollection.add(new HibernateBeanSerializer(o).getProxy());  }  return proxyCollection; }else {  return returnValue; } } private boolean isExclude(MethodInvocation mi, String propertyName)  throws Throwable { for(String excludePropertyName : excludesProperties) {  if (propertyName.equals(excludePropertyName)) {  return true;   } } return false; } private static String getPropertyName(String methodName) { String propertyName = null; if(methodName.startsWith("get")) {  propertyName = methodName.substring("get".length()); }else if (methodName.startsWith("is")) {  propertyName = methodName.substring("is".length()); }else if (methodName.startsWith("set")) {  propertyName = methodName.substring("set".length()); } return propertyName == null ? null : StringUtils.uncapitalize(propertyName); }} }

另这个类属于rapid-framework的一部分,v2.0版本的flex RemoteObject将采 用这个办法.preview版本即将发布

接受失败等于回归真实的自我,接受失败等于打破完美的面具,

使用动态代理解决Hibernate序列化,避免延迟加载问题

相关文章:

你感兴趣的文章:

标签云: