[英]Using Hibernate 4's Integrator pattern and Spring's dependency injection
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. 但是,随着Hibernate 4.0的变化,我们现在建议使用新的Integrator
接口进行服务发现。 This includes adding event listeners for triggers such as postUpdate
, postDelete
etc. 这包括为postUpdate
, postDelete
等触发器添加事件侦听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
. 我已定义的集成器将我的监听器添加到ServiceFactory
。 This is referenced in the file META-INF/services/org.hibernate.integrator.spi.Integrator
. 这在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. 我还定义了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. 我想这是因为我在实例MyListener
内部MyIntegrator
,它不拿起成分,不会自动装配组件。 However, if I try this: 但是,如果我试试这个:
@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()
. 首先,使用Spring必须执行new MyListener()
时感觉不对。 I expect to be able to define that as an autowired dependency and have Spring create a singleton for me. 我希望能够将其定义为自动连接的依赖项,并让Spring为我创建一个单例。 My question is this: 我的问题是:
What's the best approach to using dependency injection with the new Integrator interface? 在新的Integrator接口中使用依赖注入的最佳方法是什么? 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. 集成器用于构建SessionFactory,因此当他们被要求集成自己时,我猜没有可用的应用程序上下文。 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中需要的任何bean都需要以“老式”方式创建,并且不会在它们上接收自动装配。
I'm quite new to the world of Spring, would you say this is something that I should expect to see? 我对Spring这个世界很陌生,你会说这是我应该期待看到的吗? 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
? 我知道当我在SessionFactory时,我处于应用程序的不同范围,但有没有办法获得对bean的引用并启用autowire,即使我是通过new
创建它?
The solution I came up with used ApplicationContextAware
. 我提出的解决方案使用了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. 这意味着只要上下文可用, MyListener
收到对ApplicationContext
的引用,并且我在方法调用的上下文中引用了bean,而不是bean构造。 Creating a bean with new
doesn't limit this, so Spring still gives me the application context: 用new
创建bean并不限制它,所以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? 有没有更好的办法?
As stated in the comment i went another way of integrating Spring managed HibernateEventListeners. 正如评论中所述,我采用了另一种集成Spring托管的HibernateEventListeners的方法。 Here's the code: 这是代码:
The identifier interface for Spring managed Hibernate event listeners: Spring托管的Hibernate事件侦听器的标识符接口:
public interface HibernateEventListener { }
The HibernateIntegrator: 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();
...
}
}
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-managed 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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.