具有编程 bean 创建功能的通用 Java 服务不会注入 EntityManager
我有一个(希望)标准设置,其中包含一堆 @Controller
、@Service
、@Entity
和 @Repository< /code> 带注释的类,例如:
@Service
public class ChannelManager {
@Autowired
private ChannelDao channelDao;
public List<Channel> allChannels() {
return channelDao.findAll();
}
}
其中 ChannelDao
是:
public interface ChannelDao extends PersistentDao<Channel> {}
ChannelImpl
是:
@Repository
public class ChannelImpl extends PersistentImpl<Channel> implements ChannelDao {}
Channel
是:
@Entity
@Table(name = "channel")
public class Channel extends Persistent {
@Id
@Column(name = "id", nullable = false)
private Long id;
// set/get
}
PersistentDao
是:
public interface PersistentDao<T extends Persistent> {
public List<T> findAll();
}
最后,PersistentImpl
是:
public class PersistentImpl<T extends Persistent> implements PersistentDao<T> {
@PersistenceContext
protected EntityManager entityManager;
private Class<T> clazz; // gets assigned correctly
public List<T> findAll() {
return entityManager.createQuery("from " + clazz.getSimpleName()).getResultList();
}
}
所有这些都按预期工作。我正在使用
和
以及
和 persistence.xml
。基本上一切都有效。
但现在我想概括 ChannelManager,因为我有许多其他实体并且希望避免重复。例如,我还需要一个带有 List
方法。
所以我创建了这个:
@Service
public class GeneralManager<T extends PersistentDao, E extends Persistent> {
@Autowired
private AutowireCapableBeanFactory factory;
public void setFactory(AutowireCapableBeanFactory factory) {
this.factory = factory;
}
private Class<? extends T> impl;
private T dao;
public GeneralManager(Class<? extends T> impl) throws Exception {
this.impl = impl;
}
@PostConstruct
public void postCtor() {
dao = factory.createBean(impl); // seems to be created and is not null
}
public List<E> all() {
return dao.findAll();
}
}
我更新了 context.xml
<bean id="jobImpl" class="a.b.c.GeneralManager">
<property name="factory" ref="autowireFactory"/>
<constructor-arg value="a.b.c.JobImpl"/>
</bean>
<bean id="autowireFactory" class="org.springframework.beans.factory.support.DefaultListableBeanFactory"/>
<context:annotation-config/>
<context:component-scan base-package="a.b.c">
<context:exclude-filter type="regex" expression=".*GeneralManager"/>
</context:component-scan>
最后在控制器中添加了一个声明:
@Autowired
@Qualifier(value="jobImpl")
private GeneralManager<JobDao, Job> jobManager;
想象一下 Jobxxx 类与 Channelxxx 类类似。
但是,当执行 JobImpl
专门化中的 findAll()
方法时,entityManager 为 null,因此未设置某些内容正确。
所以我的问题确实是“这可以做到吗”?不过,如果有其他更好的方法来做到这一点,请启发我!
编辑:可能值得注意的是,我正在使用 Spring 3.0.5、Java 1.6.0_21-b07 和 Hibernate 3.6.2.Final
I have a (hopefully) standard set-up with a bunch of @Controller
, @Service
, @Entity
and @Repository
annotated classes, for example:
@Service
public class ChannelManager {
@Autowired
private ChannelDao channelDao;
public List<Channel> allChannels() {
return channelDao.findAll();
}
}
where ChannelDao
is:
public interface ChannelDao extends PersistentDao<Channel> {}
ChannelImpl
is:
@Repository
public class ChannelImpl extends PersistentImpl<Channel> implements ChannelDao {}
Channel
is:
@Entity
@Table(name = "channel")
public class Channel extends Persistent {
@Id
@Column(name = "id", nullable = false)
private Long id;
// set/get
}
PersistentDao
is:
public interface PersistentDao<T extends Persistent> {
public List<T> findAll();
}
and finally PersistentImpl
is:
public class PersistentImpl<T extends Persistent> implements PersistentDao<T> {
@PersistenceContext
protected EntityManager entityManager;
private Class<T> clazz; // gets assigned correctly
public List<T> findAll() {
return entityManager.createQuery("from " + clazz.getSimpleName()).getResultList();
}
}
All this works as expected. I am using <context:annotation-config/>
and <context:component-scan/>
as well as the <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" ...>
with a persistence.xml
. Basically it all works.
But now I want to generalize the ChannelManager since I have many other entities and want to avoid duplication. For example I also need a JobManager with a List<Job> allJobs() { return jobDao.findall(); }
method.
So I created this:
@Service
public class GeneralManager<T extends PersistentDao, E extends Persistent> {
@Autowired
private AutowireCapableBeanFactory factory;
public void setFactory(AutowireCapableBeanFactory factory) {
this.factory = factory;
}
private Class<? extends T> impl;
private T dao;
public GeneralManager(Class<? extends T> impl) throws Exception {
this.impl = impl;
}
@PostConstruct
public void postCtor() {
dao = factory.createBean(impl); // seems to be created and is not null
}
public List<E> all() {
return dao.findAll();
}
}
And I updated the context.xml
<bean id="jobImpl" class="a.b.c.GeneralManager">
<property name="factory" ref="autowireFactory"/>
<constructor-arg value="a.b.c.JobImpl"/>
</bean>
<bean id="autowireFactory" class="org.springframework.beans.factory.support.DefaultListableBeanFactory"/>
<context:annotation-config/>
<context:component-scan base-package="a.b.c">
<context:exclude-filter type="regex" expression=".*GeneralManager"/>
</context:component-scan>
And finally added a declaration in the controller:
@Autowired
@Qualifier(value="jobImpl")
private GeneralManager<JobDao, Job> jobManager;
Just imagine the Jobxxx classes to be similar to the Channelxxx ones.
However, when it comes to execute the findAll()
method in the JobImpl
specialization, the entityManager is null, so something is not set-up correctly.
So my question really is "can this be done"? Although if there is an alternate and nicer way to do this please enlighten me!
Edit: Might be of note that I'm using Spring 3.0.5, Java 1.6.0_21-b07 and Hibernate 3.6.2.Final
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因此,经过更多思考后,我通过显式定义 bean 走向了略有不同的方向,这是我试图避免的事情。但这对我有用。我仍然不知道我想做的事情是否因为类型擦除而无法实现。
我的代码现在看起来像:
控制器使用:
并且 context.xml 现在有:
希望这对某人有帮助!
So after thinking a bit more about it, I've gone in a slightly different direction by explicitly defining the beans which was something I was trying to avoid. But it is working for me. I still don't know if what I was trying to do was just not possible because of type erasure.
My code now looks like:
with the controller using:
and context.xml now has:
Hope this helps someone!
为什么不简单地使用 spring-data 项目呢?它完全可以满足您的需求,甚至更多。
why not simply use spring-data project? it does exactly what you need and more.