我有一个Spring MVC示例应用程序,它使用UserDaoImpl类将User类型对象保存到数据库。以下是UserDaoImpl代码。
public class UserDaoImpl implements UserDao<User> {
private EntityManagerFactory emf;
@PersistenceContext
private EntityManager em;
@Transactional
public void saveUser(User user){
em.persist(user);
}
}
我的UserDao界面看起来像这样。
public interface UserDao<User> {
public void saveUser(User user);
}
当我的UserDaoImpl类实现UserDao接口时,发生了奇怪的事情。当试图坚持它时会出现以下错误。
java.lang.ClassCastException: $Proxy71 cannot be cast to org.samith.UserDaoImpl
当我从UserDaoImpl类中删除“implements UserDao”部分时,用户会按预期持久保存到数据库。
此外,我尝试了没有User参数的UserDao接口(非通用版本)。仍然出现以上错误。
这可能是一个微不足道的问题要回答,但我正在寻找解决方案大约几个小时。
我做错了什么?
答案 0 :(得分:3)
您没有提供问题代码(或完整的堆栈跟踪),但是这个概述是这样的:
当您将类注释为@Transactional,并且Spring为您创建实例时,您获得的不是该类,而是实现该类接口的Java动态代理。 http://download.oracle.com/javase/1.3/docs/guide/reflection/proxy.html
因此,你不能将该对象强制转换为原始类型(它不再是那种类型!)而必须使用它的接口。
如果没有要实现的接口,它将为您提供该类的CGLib代理,它基本上只是您的类的运行时修改版本,因此可以分配给类本身。
搜索您正在注入或转换为UserDaoImpl类型的位置,并改为改为对UserDao的引用,它将正常工作。
我已经阅读了CGLib代理和动态Java代理之间的性能差异非常小,因此您还可以将以下内容添加到spring配置中以强制它使用CGLib代理而不是Java动态代理:
<aop:config proxy-target-class="true">
一般情况下,我建议您不要使用CGLib Proxies,而是从其界面访问您的类。松散耦合将允许您进行运行时替换,并限制您意外引入脆弱类依赖性的能力。
然而,使用Java动态代理会引入一些问题,而你正在做的事情与我正在做的事情相近,你应该知道这一点:
How to use Dynamic Proxies with JSF when the method signature contains Object ... args
答案 1 :(得分:0)
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
也为我工作。由于接受答案的所有者,这一点是proxy-target-class="true"
。但是接下来需要cglib依赖。