这是一个概念性问题,即
我正在使用Spring Application Context来实例化和管理我的对象。我有一个由以下层组成的应用程序。
模型(DAO),存储库,服务
现在在Repository和Service层中,所有Classes都实现了相应的接口,我可以通过调用相应接口的方法来调用这些层的方法,例如:
@Autowired
public IUserRepository iUserRepository;
iUserRepository.doSomething();
在我的模型(DAO)层中,我有使用
注释的类@Repository
@Entity
@Table(name = "USERS")
public class Users {
...
}
我面临的问题是流动。在我的服务层中,当我尝试从模型(DAO)层实例化一个对象,即:
Users userTest = (Users)context.getBean("users");
我得到“用户”类型的对象,但这不是“用户”对象,而是通过基于CGLIB的代理实例化的代理对象。 该代理对象具有其他属性。请参阅调试中的附图。
当我尝试将其进一步传递到我的存储库层时,我得到下面列出的错误
如果我使用运算符“new”实例化同一个类的对象,那么一切都运行良好,即我能够将该对象保存在数据库中。
user = new Users();
iUserRepository.createUser(user);
直到现在我已经知道我不在Spring中使用“new”运算符,即Spring Application context(container)shell管理所有对象但是如何处理这种情况。
我的DAO Users对象确实有一个默认构造函数但没有实现任何接口,因此没有使用JdkDynamicAopProxy,而是创建了基于CGLIB的代理。但是该代理对象以后不被接受为我的存储库的User对象,即我得到“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)
答案 0 :(得分:2)
好像你正试图通过mixin直接使用spring-data Repositories
创建一个Active Record。
虽然很多人都不接受,但恕我直言这种方法可以通过组合更好地工作,即在entites中注入存储库,而不是通过cglib代理扩展它们。
例如:
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);
}
}
请注意,您需要使用AspectJ
进行编织,因为实体通常由ORM或应用程序代码创建,而不是由Spring容器创建。
User user = new User();
user.setName("test");
user.save();
答案 1 :(得分:0)
我遇到了类似的问题。这是因为默认情况下,Hibernate使用entity.getClass().getName()
来解析实体名称,如的最后一行所示。
下面来自类CoordinatingEntityNameResolver
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();
}
}
在第一行中,您可以看到它首先尝试使用hibernate's interceptor来解析名称。
您可以自定义拦截器并覆盖实体名称解析逻辑,如下所示
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