Spring将CGLIB代理对象传递到@Repository层并休眠

Spring将CGLIB代理对象传递到@Repository层并休眠,spring,spring-aop,cglib,Spring,Spring Aop,Cglib,这更多的是一个概念性问题,即 我正在使用Spring应用程序上下文来实例化和管理我的对象。我有一个由以下几层组成的应用程序 模型(DAO)、存储库、服务 现在在存储库和服务层中,所有类都实现了相应的接口,我可以通过调用相应接口的方法来调用这些层的方法,例如: @Autowired public IUserRepository iUserRepository; iUserRepository.doSomething(); public interface ActiveRecord { v

这更多的是一个概念性问题,即

我正在使用Spring应用程序上下文来实例化和管理我的对象。我有一个由以下几层组成的应用程序

模型(DAO)、存储库、服务

现在在存储库和服务层中,所有类都实现了相应的接口,我可以通过调用相应接口的方法来调用这些层的方法,例如:

@Autowired
public IUserRepository iUserRepository;
iUserRepository.doSomething();
public interface ActiveRecord {
    void save();
    User load(Long id);
    void delete();
}

interface UserRepository extends JpaRepository<User, Long> {

}

@Configurable
class User implements ActiveRecord {
    @Id
    private Long id;
    private String name;
    @Transient @Autowired 
    private UserRepository repository;

    @Override
    public void save() {
        this.repository.save(this);

    }
    @Override
    public User load(Long id) {
        return repository.findOne(id);

    }
    @Override
    public void delete() {
        this.repository.delete(this);
    }
}
在我的模型(DAO)层中,我有用注释的类

@Repository
@Entity
@Table(name = "USERS")
public class Users {
...
}
我面临的问题是流动性。在我的服务层中,当我尝试从模型(DAO)层实例化对象时,即:

Users userTest =  (Users)context.getBean("users");
我得到了类型为“Users”的对象,但它并不完全是“Users”对象,而是通过基于CGLIB的代理实例化的代理对象。 该代理对象具有其他属性。请参阅调试过程中附带的图片。

当我试图将它进一步传递到我的存储库层时,我得到下面列出的错误

如果我用操作符“new”实例化同一类的对象,那么一切都很好,即我能够将该对象保存在数据库中

user = new Users();

iUserRepository.createUser(user);
到目前为止,我已经了解到我的shell没有在Spring中使用“new”操作符,即Spring应用程序上下文(容器)shell管理所有对象,但是如何处理这种情况

我的DAO用户对象有一个默认构造函数,但没有实现任何接口,因此没有使用JDKDDynamicAOPProxy,而是创建了基于CGLIB的代理。但该代理对象稍后不会被接受为我的存储库的用户对象,即,我收到“org.hibernate.MappingException:Unknown entity:”错误消息

问题是什么是“正确的”构造/星座,即使用新操作符是否可以,或者我是否犯了一些我还没有意识到的典型错误

2014-10-12 11:13:53.707 ERROR 8388 --- [           main] o.s.R.account.UserRepositoryImpl         : Exception

org.hibernate.MappingException: Unknown entity: org.syncServer.Model.acount.Users$$EnhancerBySpringCGLIB$$54139ff4
    at org.hibernate.internal.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:1095)
    at org.hibernate.internal.SessionImpl.getEntityPersister(SessionImpl.java:1439)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:116)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:209)
    at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:194)
    at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
    at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:711)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:703)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:698)
    at org.syncServer.Repository.account.UserRepositoryImpl.create(UserRepositoryImpl.java:186)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy76.create(Unknown Source)
    at org.syncServer.Service.account.UserServiceImpl.create(UserServiceImpl.java:266)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy81.create(Unknown Source)
    at org.syncServer.core.Tests.createUser(Tests.java:44)
    at org.syncServer.core.Application.main(Application.java:95)

似乎您正试图通过直接将JPA实体与spring数据
存储库混入来创建一个新的JPA实体

尽管许多人不接受这种方法,但IMHO认为这种方法可以通过组合更好地工作,即在实体中注入存储库,而不是通过cglib代理来扩展它们

例如:

@Autowired
public IUserRepository iUserRepository;
iUserRepository.doSomething();
public interface ActiveRecord {
    void save();
    User load(Long id);
    void delete();
}

interface UserRepository extends JpaRepository<User, Long> {

}

@Configurable
class User implements ActiveRecord {
    @Id
    private Long id;
    private String name;
    @Transient @Autowired 
    private UserRepository repository;

    @Override
    public void save() {
        this.repository.save(this);

    }
    @Override
    public User load(Long id) {
        return repository.findOne(id);

    }
    @Override
    public void delete() {
        this.repository.delete(this);
    }
}

我遇到了类似的问题。这是因为Hibernate默认使用
entity.getClass().getName()
解析实体名称,如图中最后一行所示 下面的反编译代码来自类
CoordinationTityNameResolver

 public String resolveEntityName(Object entity) {
        String entityName = this.interceptor.getEntityName(entity);
        if (entityName != null) {
            return entityName;
        } else {
            Iterator var3 = this.sessionFactory.getMetamodel().getEntityNameResolvers().iterator();

            while(var3.hasNext()) {
                EntityNameResolver resolver = (EntityNameResolver)var3.next();
                entityName = resolver.resolveEntityName(entity);
                if (entityName != null) {
                    break;
                }
            }

            return entityName != null ? entityName : entity.getClass().getName();
        }
    }
在第一行中,您可以看到它尝试使用first解析名称

您可以自定义拦截器并覆盖实体名称解析逻辑,如下所示

public class EntityProxySupportHibernateInterceptor extends EmptyInterceptor {
    @Override
    public String getEntityName(Object object) {
        return AopUtils.getTargetClass(object).getName();
    }
}
在我的例子中,我使用Spring的
AopUitls.getTargetClass()
,因为我使用Spring的aop代理由实体包装。如果使用其他类型的代理(如原始cglib),则可以根据需要更改实现

然后在
application.properties中注册它

spring.jpa.properties.hibernate.ejb.interceptor=com.your.package.EntityProxySupportHibernateInterceptor

为什么不自己创建一个
用户的新实例呢?使用
新用户()
没有什么问题。还有,为什么您的
用户
会成为
@存储库
?。您希望连接您的应用程序(服务、存储库)和基础结构(队列、数据源),但通常不是您的业务对象。您好,Deinum,我选择了模型(DAO)的“存储库”注释,因为这是模型(DAO)和存储库层的推荐注释。我在Stackoverflow上找到了这个建议。我可以将其标记为组件,但该注释并不反映该类的用途。由于我对Spring基本上是新手,所以我并不知道正确的方法是什么,但问题仍然是为什么Spring不将代理对象识别为用户对象,而是将hibernate异常“org.hibernate.MappingException:Unknown entity:”您有一个应该用
@repository
注释的存储库。通常,您的模型不是spring管理的(除非您使用富域或活动记录等)。事实上,您使用spring或di并不意味着每个类都需要管理……Deinum,感谢您的回复,我想这就是我要寻找的,即确认“通常”模型不应由spring管理。但是,是否有可能使用spring管理模型?是的,这是什么?若泽谢谢你的评论。我会考虑我的代码中的方法。