簡體   English   中英

摘要DAO模式和Spring的“代理無法轉換為......”問題!

[英]Abstract DAO pattern and Spring's “Proxy cannot be cast to …” problem!

我知道這經常被問到,但我找不到一個有效的解決方案:

這是我的AbstractDAO:

public interface AbstractDao<T>
{
  public T get(Serializable id);
  //other CRUD operations
}

這是我的JPA實現:

public abstract class AbstractDaoJpaImpl<T> implements AbstractDao<T> , Serializable
{
  protected EntityManager em;

  protected Class<T> clazz;

  @SuppressWarnings("unchecked")
  public AbstractDaoJpaImpl()
  {
    ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
    this.clazz = (Class<T>) genericSuperclass.getActualTypeArguments()[0];
  }

  public abstract void setEntityManager(EntityManager em);  
  //implementations skipped
}

這是一個實體的道:

public interface PersonDao extends AbstractDao<Person>
{
  //empty
}

這是它的實現:

@Repository
public class PersonDaoImpl extends AbstractDaoJpaImpl<Person> implements PersonDao , OtherInterface
{
  @PersistenceContext(unitName="company")
  @Override
  public void setEntityManager(EntityManager em)
  {
    this.em = em;
  }

  @Override // implements OtherInterface.additionalMethods()
  public additionalMethods()
  {
    // implements...
  }
}

整個架構很簡單:

接口AbstractDao定義了簡單的CRUD方法。

接口PersonDao無需任何插件方法擴展AbstractDAO。

class AbstractDaoJpaImpl定義了JPA的AbstractDao實現

class PersonDaoImpl擴展AbstractDaoJpaImpl並實現PersonDao AND OtherInterface,它添加了aditionalMethods() ...

如果,PersonDaoImpl只實現PersonDao,而不實現OtherInterface.additionalMethods(),一切正常。

我可以用

<tx:annotation-driven transaction-manager="transactionManager" /> 

在我的spring的XML文件中。

但是,PersonDaoImpl實現了OtherInterface,在測試/運行時,我必須將DAO從PersonDao轉換為PersonDaoImpl或OtherInterfaces ,例如:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:app.xml"})
@TransactionConfiguration(transactionManager="transactionManager" , defaultRollback=false)
public class PersonDaoTest
{
  @Inject 
  PersonDao dao;

  @Test
  public void testAdditionalMethod()
  {
    PersonDaoImpl impl = (PersonDaoImpl) dao;
    System.out.println(impl.additionalMethod(...));
  }
}

(PersonDaoImpl) dao拋出“Proxy無法強制轉換為PersonDaoImpl”異常時,會出現問題:

java.lang.ClassCastException: $Proxy36 cannot be cast to foobar.PersonDaoImpl
    at foobar.PersonDaoTest.testAdditionalMethod(PersonDaoTest.java:36)

googleing時經常會問這個問題,每個人都建議在<tx:annotation-driven>添加proxy-target-class="true"

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"  />

這將使用CGLIB而不是JDK的動態代理。

但是在初始化Spring時會拋出另一個異常:

Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

在AbstractDaoJpaImpl的構造函數中:

ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();

每個問題都停在這里,我現在找不到任何有效的解決方案。

誰能給我一個有效的解決方案? 非常感謝 !

環境:Spring-3.0.4,javaee-api-6.0,javax.inject,cglib-2.2,hibernate-jpa-2.0-api-1.0.0,

你正在解決錯誤的問題。 代理豆並不意味着以某種方式投射到原始類。 這將打破依賴注入的整個點。 畢竟:當您將依賴項指定為接口時,您正在請求滿足合同的bean,而不是實現細節。 將它轉換為原始的bean類可以打破這種松散的耦合。

您說其他方法是由您調用OtherInterface的接口備份的,那么為什么不使用它呢? 畢竟,代理將實現所有目標類的接口,而不僅僅是注入的接口。

@Test
public void testAdditionalMethod()
{
    OtherInterface oi = (OtherInterface) dao;
    System.out.println(oi.additionalMethod(...));
}

基本上你有這些選項(從清潔到臟):

  1. 分離您的顧慮並為不同的界面使用不同的bean
  2. 創建一個擴展OtherInterfacePersonDao的元接口,讓bean實現該元接口
  3. 在任何給定時刻將bean轉換為您需要的接口。

是的春天總是創建代理類,這就是它如何實際發現非侵入式編織和aop by xml config ...嘗試在春季文檔中搜索該錯誤,那里有不遵守規則和解決方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM