程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用動態代理解決Hibernate序列化,避免延遲加載問題

使用動態代理解決Hibernate序列化,避免延遲加載問題

編輯:關於JAVA

在使用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 null
Role proxyRole = (Role) new  HibernateBeanSerializer<Role>(role).getProxy ();
assertNotNull(role.getResource());
assertNull (proxyRole.getResource()); //延遲加載,為null
Hibernate.initialize (role.getResource()); //抓取進來  
assertNotNull (proxyRole.getResource()); //不為null
//role為原始對象
role = (Role)roleDao.getById(new Long(1));
//生成的動態代理proxyRole,訪問 延遲加載的屬性將return null
Role proxyRole = (Role)new HibernateBeanSerializer<Role>(role).getProxy ();
assertNotNull(role.getResource());
assertNull (proxyRole.getResource()); //延遲加載,為null
Hibernate.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值. 
* 使用: 
* <pre>
* Blog proxyBlog = new HibernateBeanSerializer(blog).getProxy();
* </pre>
* @author badqiu 
* @param <T>
*/  
public  class  HibernateBeanSerializer <T> {
  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<Map.Entry> 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值.
* 使用:
* <pre>
* Blog proxyBlog = new HibernateBeanSerializer(blog).getProxy();
* </pre>
* @author badqiu
* @param <T>
*/
public class HibernateBeanSerializer <T> {
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<Map.Entry> 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版本即將發布

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved