我有一个 Spring MVC 示例应用程序,它使用 UserDaoImpl 类将用户类型对象保存到数据库。以下是 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 接口(interface)时,发生了奇怪的事情。当尝试坚持时,它会出现以下错误。
java.lang.ClassCastException: $Proxy71 cannot be cast to org.samith.UserDaoImpl
当我从 UserDaoImpl 类中删除“implements UserDao”部分时,用户会按预期持久保存到数据库中。
我还尝试了没有 User 参数的 UserDao 接口(interface)(非通用版本)。仍然出现上述错误。
这可能是一个需要回答的微不足道的问题,但我花了大约几个小时挠头寻找解决方案。
我做错了什么??
最佳答案
您没有提供问题代码(或完整的堆栈跟踪),但概要是这样的:
当您将类注释为@Transactional 时,Spring 会为您创建一个实例,您得到的不是该类,而是实现该类接口(interface)的Java 动态代理。 http://download.oracle.com/javase/1.3/docs/guide/reflection/proxy.html
因此,您无法将该对象转换为原始类型(不再是该类型!),而必须改用它的接口(interface)。
如果没有要实现的接口(interface),它将为您提供该类的 CGLib 代理,它基本上只是您类的运行时修改版本,因此可分配给类本身。
搜索要注入(inject)的位置,或强制转换为类型 UserDaoImpl,然后更改对 UserDao 的引用,它将正常工作。
我读过 CGLib 代理和动态 Java 代理之间的性能差异非常小,因此您还可以将以下内容添加到您的 spring 配置中以强制它使用 CGLib 代理而不是 Java 动态代理:
<aop:config proxy-target-class="true">
不过,一般来说,我建议您不要使用 CGLib 代理,而是从类的界面访问您的类。松散耦合将允许您进行运行时替换,并限制您意外引入脆弱的类依赖性的能力。
然而,使用 Java 动态代理会引入一些问题,您所做的与我所做的非常接近,您应该意识到这一点:
How to use Dynamic Proxies with JSF when the method signature contains Object ... args
关于java - Spring @Transactional 持久方法不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7061872/