java 使用 Hibernate 4 的 Integrator 模式和 Spring 的依赖注入
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16019820/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using Hibernate 4's Integrator pattern and Spring's dependency injection
提问by EMMERICH
I'm used to using Spring to do my dependency injection like so:
我习惯于使用 Spring 进行依赖注入,如下所示:
<context:component-scan base-package="org.emmerich.myapp" />
and then annotating my dependent classes with Autowired
like so:
然后Autowired
像这样注释我的依赖类:
public class DependentClass {
@Autowired
private Dependency dependency;
}
However, with the changes in Hibernate 4.0, we're now advised to use the new Integrator
interface for service discovery. This includes adding event listeners for triggers such as postUpdate
, postDelete
etc.
但是,随着 Hibernate 4.0 中的变化,我们现在建议使用新的Integrator
接口进行服务发现。这包括添加事件侦听器触发器如postUpdate
,postDelete
等
Unfortunately, this doesn't play nicely with dependency injection through annotated dependencies. I have the following setup:
不幸的是,这与通过带注释的依赖项进行的依赖项注入并不能很好地配合。我有以下设置:
An integrator I have defined to add my listener to the ServiceFactory
. This is referenced in the file META-INF/services/org.hibernate.integrator.spi.Integrator
.
我定义了一个集成器,用于将我的侦听器添加到ServiceFactory
. 这在文件中被引用META-INF/services/org.hibernate.integrator.spi.Integrator
。
public class MyIntegrator implements Integrator {
private MyListener listener;
public MyIntegrator() {
listener = new MyListener();
}
@Override
public void integrate(Configuration configuration,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
final EventListenerRegistry eventRegistry =
serviceRegistry.getService(EventListenerRegistry.class);
eventRegistry.prependListeners(EventType.POST_COMMIT_INSERT, listener);
}
I also have defined the class MyListener
, which looks like your typical event listener.
我还定义了 class MyListener
,它看起来像典型的事件侦听器。
@Component
public class MyListener implements PostInsertEventListener {
@Autowired
private Dependent dependent;
public void onPostInsert(PostInsertEvent event) {
// dependent == null
}
}
Unforunately, as shown by the comment, this doesn't work. I guess it's because I'm instantiating MyListener
inside MyIntegrator
, it doesn't pick up the component and doesn't autowire components. However, if I try this:
不幸的是,如评论所示,这不起作用。我想这是因为我在MyListener
inside实例化MyIntegrator
,它不会拾取组件并且不会自动装配组件。但是,如果我尝试这样做:
@Component
public class MyIntegrator {
@Autowired
private MyListener listener;
...
}
Then the listener isn't autowired.
然后侦听器不会自动装配。
Firstly, it feels wrong whilst using Spring to have to do new MyListener()
. I expect to be able to define that as an autowired dependency and have Spring create a singleton for me. My question is this:
首先,在使用 Spring 时感觉不对new MyListener()
。我希望能够将其定义为自动装配的依赖项,并让 Spring 为我创建一个单例。我的问题是这样的:
What's the best approach to using dependency injection with the new Integrator interface? The Integrators are used to build a SessionFactory, and so when they're asked to integrate themselves I guess there isn't an application context available. Because of that, any beans I require in the Integrator need to be created the "old fashioned" way and won't receive the autowiring on them.
在新的 Integrator 接口中使用依赖注入的最佳方法是什么?集成器用于构建 SessionFactory,因此当他们被要求集成自己时,我猜没有可用的应用程序上下文。因此,我在 Integrator 中需要的任何 bean 都需要以“老式”方式创建,并且不会收到自动装配。
I'm quite new to the world of Spring, would you say this is something that I should expect to see? I understand that I'm in a different scope of the application when I'm in the SessionFactory, but is there a way to obtain a reference to the bean and enable autowire even though I'm creating it via new
?
我对 Spring 的世界很陌生,你会说这是我应该期待看到的吗?我知道当我在 SessionFactory 中时,我处于应用程序的不同范围内,但是有没有办法获取对 bean 的引用并启用自动装配,即使我是通过new
.
The solution I came up with used ApplicationContextAware
. It meant that MyListener
received a reference to the ApplicationContext
whenever the context was available, and I referenced the beans from the context on method calls, rather than on bean construction. Creating a bean with new
doesn't limit this, so Spring still gives me the application context:
我想出的解决方案使用了ApplicationContextAware
. 这意味着只要上下文可用,就会MyListener
收到对 的引用ApplicationContext
,并且我在方法调用时从上下文中引用了 bean,而不是在 bean 构造上。创建一个 bean withnew
并没有限制这个,所以 Spring 仍然给了我应用程序上下文:
@Component
public class MyListener implements PostInsertEventListener, ApplicationContextAware {
private static ApplicationContext context;
public void onPostInsert(PostInsertEvent event) {
// getDependent() == correct!
}
public void setApplicationContext(ApplicationContext context) throws BeanException {
this.context = context;
}
public Dependent getDependent() {
return context.getBean(Dependent.class);
}
}
Is there a better way?
有没有更好的办法?
回答by Martin Frey
As stated in the comment i went another way of integrating Spring managed HibernateEventListeners. Here's the code:
正如评论中所述,我采用了另一种集成 Spring 管理的 HibernateEventListeners 的方式。这是代码:
The identifier interface for Spring managed Hibernate event listeners:
Spring 管理的 Hibernate 事件侦听器的标识符接口:
public interface HibernateEventListener { }
The HibernateIntegrator:
休眠集成器:
@Service
public class HibernateSpringIntegrator {
private static final Logger log = LoggerFactory.getLogger(HibernateSpringIntegrator.class);
@Autowired
private HibernateEntityManagerFactory entityManagerFactory;
@Autowired
private HibernateSpringIntegratorRegistry hibernateSpringIntegratorRegistry;
@PostConstruct
public void registerListeners() {
log.debug("Registering Spring managed HibernateEventListeners");
EventListenerRegistry listenerRegistry = ((SessionFactoryImpl) entityManagerFactory
.getSessionFactory()).getServiceRegistry().getService(
EventListenerRegistry.class);
List<HibernateEventListener> eventListeners = hibernateSpringIntegratorRegistry
.getHibernateEventListeners();
for (HibernateEventListener hel : eventListeners) {
log.debug("Registering: {}", hel.getClass());
if (PreInsertEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.PRE_INSERT,
(PreInsertEventListener) hel);
}
if (PreUpdateEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.PRE_UPDATE,
(PreUpdateEventListener) hel);
}
if (PreDeleteEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.PRE_DELETE,
(PreDeleteEventListener) hel);
}
if (PostInsertEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.POST_INSERT,
(PostInsertEventListener) hel);
}
if (PostUpdateEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.POST_UPDATE,
(PostUpdateEventListener) hel);
}
if (PostDeleteEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.POST_DELETE,
(PostDeleteEventListener) hel);
}
// Currently we do not need other types of eventListeners. Else this method needs to be extended.
}
}
}
The "Registry":
“注册表”:
@Component
public class HibernateSpringIntegratorRegistry {
@Autowired(required = false)
private List<HibernateEventListener> hibernateEventListeners;
public List<HibernateEventListener> getHibernateEventListeners() {
if (hibernateEventListeners == null) {
return Collections.emptyList();
}
return hibernateEventListeners;
}
}
And here's an example implementation:
这是一个示例实现:
@Component
public class MailGenerationEventListener implements HibernateEventListener,
PostDeleteEventListener, PostInsertEventListener, PostUpdateEventListener {
@Override
public void onPostDelete(PostDeleteEvent event) {
Class<?> entityClass = event.getEntity().getClass();
...
}
@Override
public void onPostInsert(PostInsertEvent event) {
Class<?> entityClass = event.getEntity().getClass();
...
}
@Override
public void onPostUpdate(PostUpdateEvent event) {
Class<?> entityClass = event.getEntity().getClass();
...
}
}
回答by Andrew
During an upgrade from hibernate 3.6 to 4.2, we needed to have a custom validator that uses spring-managed beans by doing the following configuration:
在从 hibernate 3.6 升级到 4.2 的过程中,我们需要通过执行以下配置来拥有一个使用 spring 管理的 bean 的自定义验证器:
<!-- Make our validators use DI if necessary -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- other props -->
<property name="hibernateProperties">
<map>
<entry key="javax.persistence.validation.factory" value-ref="validator" />
</map>
</property>
</bean>