2010-04-06 27 views
0

其實,這不是一個問題,但我真的需要你的意見在事...... 我把他的文章在這裏,因爲我知道你總是活躍,所以請不要認爲這是一個不好的問題,並與我分享你的意見。使用動態代理集中JPA代碼

我使用的Java動態代理集中JPA的,我在單機模式中使用的代碼,而這裏的動態代理代碼:

package com.forat.service; 

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

import javax.persistence.EntityManager; 
import javax.persistence.EntityManagerFactory; 
import javax.persistence.EntityTransaction; 
import javax.persistence.Persistence; 

import com.forat.service.exceptions.DAOException; 

/** 
* Example of usage : 
* <pre> 
* OnlineFromService onfromService = 
*   (OnlineFromService) DAOProxy.newInstance(new OnlineFormServiceImpl()); 
*  try { 
*   Student s = new Student(); 
*   s.setName("Mohammed"); 
*   s.setNationalNumber("123456"); 
*   onfromService.addStudent(s);  
*  }catch (Exception ex) { 
*   System.out.println(ex.getMessage()); 
*  } 
*</pre> 
* @author mohammed hewedy 
* 
*/ 
public class DAOProxy implements InvocationHandler{ 

    private Object object; 
    private Logger logger = Logger.getLogger(this.getClass().getSimpleName()); 

    private DAOProxy(Object object) { 
     this.object = object; 
    } 

    public static Object newInstance(Object object) { 
     return Proxy.newProxyInstance(object.getClass().getClassLoader(), 
        object.getClass().getInterfaces(), new DAOProxy(object)); 
    } 

    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
     EntityManagerFactory emf = null; 
     EntityManager em = null; 
     EntityTransaction et = null; 
     Object result = null; 
     try { 
      emf = Persistence.createEntityManagerFactory(Constants.UNIT_NAME); 
      em = emf.createEntityManager();; 
      Method entityManagerSetter = object.getClass(). 
       getDeclaredMethod(Constants.ENTITY_MANAGER_SETTER_METHOD, EntityManager.class); 
      entityManagerSetter.invoke(object, em); 
      et = em.getTransaction(); 
      et.begin(); 
      result = method.invoke(object, args); 
      et.commit(); 
      return result; 
     }catch (Exception ex) { 
      et.rollback(); 
      Throwable cause = ex.getCause(); 
      logger.log(Level.SEVERE, cause.getMessage()); 
      if (cause instanceof DAOException) 
       throw new DAOException(cause.getMessage(), cause); 
      else 
       throw new RuntimeException(cause.getMessage(), cause); 
     }finally { 
      em.close(); 
      emf.close(); 
     } 
    } 
} 

這裏是一個包含更多信息的鏈接(http://m-hewedy.blogspot.com/2010/04/using-dynamic-proxies-to-centralize-jpa.html

所以,請給我你的意見。

謝謝。

+0

您是否問使用動態代理來集中化JPA代碼是個好主意?還是你要求對你的代碼進行建設性的批評?或者,你是否在尋找過去曾使用類似方法的人的戰爭故事? – 2010-05-09 21:19:32

+0

當然我要求建設性的批評 – 2010-05-11 02:51:59

回答

1

所以,你已經封裝的事務劃分邏輯在一個地方,並使用動態代理,加強與交易管理現有的服務和減少樣板代碼,對不對?

對我來說聽起來相當不錯。實際上,當我們談到declarative transaction demarcation時,像Spring或EJB這樣的容器是非常相似的。按照實施方式,您可以使用動態代理或字節代碼工具,甚至使用AspectJ。我曾經爲一個微小的測試框架做了一次非常相似的事情。這是關於它的blog post

,我看到的最棘手的部分是:

1)回滾只有。根據JPA規範,實體交易可以被標記爲「rollback only」。這樣的交易永遠不會提交。所以,我覺得你應該檢查這兩個之間的線路:

result = method.invoke(object, args); 
et.commit(); 

2)重入。大多數具有聲明性事務的系統實現的語義只有在沒有一個事務處於活動狀態時纔會啓動事務(請參見EJB annotations的此列表中的「必需」)。看起來你應該在你的邏輯中檢查isActive

3)異常處理。要非常小心動態代理中的異常傳播。代理應儘可能對客戶透明。如果DAOException以外的異常泄漏出DAO,則代理將將其轉換爲RuntimeException。對我來說聽起來並不理想。也不要混淆了異常,因爲invoke失敗,並通過調用包裹之外,我認爲你應該重新擲原樣:

catch (InvocationTargetException e) 
{ 
    Throwable nested = e.getTargetException(); 
    throw nested; 
} 

結論:使用動態代理這一想法情景聽起來不錯。但我懷疑有幾件事要仔細檢查你的代碼(我不記得有關動態代理的JPA規範和異常處理的所有細節,但有一些棘手的情況)。這種代碼可以隱藏細微的錯誤,所以值得花時間讓它變得防不勝防。

+0

如果您不介意,我已將您寶貴的回覆複製到我的博客: http://m-hewedy.blogspot.com/2010/04using-dynamic-proxies-to-centralize-jpa.html – 2010-05-12 13:41:04

+0

順便說一句,我剛剛提到它。 – 2010-05-12 13:48:12

0

我已經在過去使用類似的東西,但編碼爲Hibernate的API(這是預JPA)。大多數DAO類型的數據訪問都由一個以對象類型E.g命名的接口進行管理。 CustomerPersistence用於管理客戶實例。諸如findXXX之類的方法映射到命名查詢,方法中的參數名稱映射到查詢中的參數。

接口的實現是代理,其中所使用的接口的名稱,方法名稱,參數名稱等。調用休眠API中適當的方法。

它節省了大量的樣板的編碼,具有直觀映射到底層數據訪問框架,併爲數據訪問層的非常容易嘲笑。

所以,我絕對是使用代理的「大拇指」。

+0

感謝您的評論。 – 2010-05-11 02:53:15