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