当前位置: 首页 > 面试题库 >

抽象的DAO模式和Spring的“代理不能转换为...”问题!

澹台正真
2023-03-14
问题内容

我知道这经常被问到,但是我找不到可行的解决方案:

这是我的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,而没有任何附加方法。

AbstractDaoJpaImpl 定义JPA对AbstractDao的实现

PersonDaoImpl 扩展AbstractDaoJpaImpl并实现PersonDao
和OtherInterface,这增加了aditionalMethods()

如果,PersonDaoImpl仅实现PersonDao,而没有实现OtherInterface.additionalMethods(),则一切正常。

我可以用

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

在我春天的XML文件中。

但是,PersonDaoImpl实现OtherInterface(s),在测试/运行时,我
必须将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,将引发“代理无法强制转换为PersonDaoImpl”异常:

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

谷歌搜索时经常问这个问题,每个人都建议添加proxy-target-class="true"<tx:annotation-driven>

<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,而不是实现详细信息。将其强制转换为原始的Bean类会破坏这种松散的耦合。

您是说其他方法由您调用的接口备份OtherInterface,那么为什么不使用它呢?毕竟,代理将实现所有目标类的接口,而不仅仅是注入的接口。

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

基本上,您可以使用以下选项(从干净到肮脏不等):

  1. 分开您的顾虑并为不同的接口使用不同的bean
  2. 创建延伸的metainterface OtherInterfacePersonDao让你的bean实现一个metainterface
  3. 在任何给定时刻将bean投射到所需的接口。


 类似资料:
  • 问题内容: 我正在使用Spring来为专门用于使用Hibernate的DAO类的依赖关系进行接线,但是却遇到了一个让我感到困惑的异常: $ Proxy58无法转换为UserDao 我的DAO的配置如下: 我有一个接口,抽象基类和最终实现,如下所示。 接口: 抽象基类: 实现方式: 以下引发上述异常: UserDao dao =(UserDao)context.getBean(“ userDao”)

  • 1. 前言 大家好,我们学习了 AOP 的概念,理解了 AOP 的作用,明白了什么是 AOP 面向切面编程,目的是进行解耦,可以自由地对某个功能方法做增强,而它的设计模式就是代理模式。 那么本小节我们就学习 AOP 设计模式之代理模式,明白代理模式的含义,掌握代理模式的语法,同时明白它的应用场景。 2. 代理模式介绍 3.1 概念解释 代理名词解释为:以被代理人名义,在授权范围内与第三方实施行为。

  • Liskov替代原理(LSP)说: 先决条件不能在子类型中得到加强。 在C#中,我可能违反以下整个原则: 但是,如果是一种方法,会发生什么呢 现在是无合同的。或者它的合同就是一切允许的。 那么,前提条件是否违反了Liskov替代原则?

  • 问题内容: 我有一个抽象的DAO类,它使用参数化类型(实体)和(主键)。在每个实体中我都有一个。我想动态调用此命名查询而不知道其确切名称和参数名称。 例如,假设以下实体 和这个 我应该如何实现该方法,以便不需要知道确切的名称和参数名称? 问题答案: 在您的示例中,命名查询的命名约定通常为“ City.findByName”,因此,我将尝试更改命名查询以遵循此模式。然后,此查询的参数也应具有相同的名

  • 有人有一个通用的例子吗?通过看到这样的例子,一定会明白我们真的需要使用代理模式吗