26

我正在使用 Spring 专门为使用 Hibernate 的 DAO 类连接依赖项,但我遇到了一个让我感到困惑的异常:

$Proxy58 无法转换为 UserDao

我的DAO配置如下:

<bean id="userDao" class="com.domain.app.dao.UserDao">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

我有一个接口、抽象基类和一个最终实现,如下所示。

界面:

public interface Dao {
    public void save(Object object);
    public Object load(long id);
    public void delete(Object object);
    public void setSessionFactory(SessionFactory sessionFactory);
}

抽象基类:

public abstract class BaseDao implements Dao {

    private SessionFactory sessionFactory;

    @Transactional
    @Override
    public void save(Object object) {
        PersistentEntity obj = (PersistentEntity) object;
        currentSession().saveOrUpdate(obj);
    }

    @Transactional
    @Override
    public abstract Object load(long id);

    @Transactional
    @Override
    public void delete(Object object) {
        // TODO: this method!
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public Session currentSession() {
        return sessionFactory.getCurrentSession();
    }

}

执行:

public class UserDao extends BaseDao implements Dao {

    @Transactional(readOnly=true)
    @Override
    public Object load(long id) {
        Object user = currentSession().get(User.class, id);
        return user;
    }

}

以下抛出上述异常:

UserDao dao = (UserDao) context.getBean("userDao");

但是,这不会引发异常:

Dao dao = (Dao) context.getBean("userDao");

如果有人可以就为什么会发生这种异常提供任何帮助或指导,我将不胜感激。

4

2 回答 2

53

Spring 默认使用JDK 动态代理$Proxy58是其中之一),只能代理接口。这意味着动态创建的类型$Proxy58将实现一个或多个由包装/目标类 ( UserDao) 实现的接口,但它不会是它的实际子类。这就是为什么您可以将userDaobean 强制转换为Dao interface而不是UserDao class的原因。

您可以使用<tx:annotation-driven proxy-target-class="true"/>来指示 Spring 使用作为代理类的实际子类的 CGLIB 代理,但我认为针对接口进行编程是更好的做法。如果您需要访问代理类中未在其中一个接口中声明的某些方法,您应该首先问自己,为什么会这样?
(另外,在上面的代码中,没有引入新方法UserDao,因此无论如何将 bean 转换为这种具体的实现类型是没有意义的。)

在官方Spring 参考中查看更多关于不同代理机制的信息。

于 2013-04-16T22:06:03.440 回答
10

我正在编写单元测试,并且需要能够为某些调用删除 DAO。根据这个家伙的帖子: http ://www.techper.net/2009/06/05/how-to-acess-target-object-behind-a-spring-proxy/ 我使用了他提供的方法:

@SuppressWarnings({"unchecked"})
protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
  if (AopUtils.isJdkDynamicProxy(proxy)) {
    return (T) ((Advised)proxy).getTargetSource().getTarget();
  } else {
    return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class
  }
}

然后你可以很容易地用代理调用它,得到代理后面的对象,并根据需要直接操作其中的对象。

于 2016-06-02T23:26:56.013 回答