我正在使用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”);
如果有人可以提供任何有关此例外情况的帮助或指导,我将非常感激。
答案 0 :(得分:49)
Spring默认使用JDK dynamic proxies($Proxy58
就是其中之一),它只能代理接口。这意味着动态创建的类型$Proxy58
将实现包装/目标类(UserDao
)实现的一个或多个接口,但它不会成为它的实际子类。这基本上就是为什么你可以将userDao
bean转换为Dao
接口,而不是转发给UserDao
类
您可以使用<tx:annotation-driven proxy-target-class="true"/>
指示Spring使用作为代理类的实际子类的CGLIB代理,但我认为对接口进行编程是更好的做法。如果你需要从代理类中访问一些未在其中一个接口中声明的方法,你应该首先问问自己,为什么会出现这种情况?
(另外,在上面的代码中,UserDao
中没有引入新方法,所以无论如何都没有必要将bean转换为这个具体的实现类型。)
在官方Spring reference中查看有关不同代理机制的更多信息。
答案 1 :(得分:6)
我正在编写单元测试,并且需要能够为某些调用存根DAO。 Per This guys发表: 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
}
}
然后您可以使用代理轻松调用它并获取代理后面的对象并根据需要直接操作其中的对象。