使用Hibernate 4的Integrator模式和Spring的依赖注入 [英] Using Hibernate 4's Integrator pattern and Spring's dependency injection

查看:227
本文介绍了使用Hibernate 4的Integrator模式和Spring的依赖注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 < context:component-scan base。

我习惯于使用Spring来执行依赖注入。 -package =org.emmerich.myapp/>

然后用 Autowired 注释我的依赖类,像这样:

  public class DependentClass {

@Autowired
private依赖关系依赖;


$ / code>

然而,随着Hibernate 4.0的变化,我们现在建议使用新的 Integrator 界面进行服务发现。这包括为 postUpdate postDelete 等触发器添加事件侦听器。



不幸的是,这不能很好地通过注释依赖关系进行依赖注入。我有以下设置:



我已经定义了一个集成器,用于将侦听器添加到 ServiceFactory 中。这是在文件 META-INF / services / org.hibernate.integrator.spi.Integrator 中引用的。

  public class MyIntegrator实现Integrator {

私有MyListener侦听器;

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);


我也定义了类

  @Component 
public class MyListener MyListener
,看起来像您的典型事件侦听器。实现PostInsertEventListener {

@Autowired
私有依赖;

public void onPostInsert(PostInsertEvent event){
// dependent == null
}

}

不幸的是,如评论所示,这不起作用。我想这是因为我在 MyIntegrator 中实例化 MyListener ,它没有拾取组件,也没有自动装配组件。但是,如果我尝试这样做:

  @Component 
public class MyIntegrator {

@ Autowired
私有MyListener侦听器;

...
}

然后, t自动装配。

首先,在使用Spring必须执行 new MyListener()时感觉不对。我希望能够将它定义为自动装配的依赖关系,并让Spring为我创建一个单例。我的问题是这样的:

使用依赖注入与新的Integrator接口的最佳方法是什么?集成器用于构建SessionFactory,因此当它们被要求集成它们自己时,我认为没有可用的应用程序上下文。正因为如此,我需要在Integrator中需要的任何bean都需要以老式方式创建,并且不会收到它们的自动装配。



我很安静对于Spring的新世界来说,你会说这是我应该期待看到的东西吗?我了解到,当我在SessionFactory中时,我处于应用程序的不同范围内,但是有一种方法可以获取对bean的引用并启用autowire,即使我通过创建它,新



我使用的解决方案是使用 ApplicationContextAware 。这意味着只要上下文可用, MyListener 就会收到对 ApplicationContext 的引用,并且我从上下文中引用了bean在方法调用上,而不是在bean构造上。使用 new 创建一个bean并不限制这个,所以Spring仍然给了我应用程序上下文:

  @Component 
public class MyListener实现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);
}

}

有没有更好的方法? / p>

解决方案

正如评论中所述,我采用了另一种集成Spring管理HibernateEventListeners的方法。以下是代码:



Spring管理的Hibernate事件监听器的标识符接口:

  public interface HibernateEventListener {} 

HibernateIntegrator:

  @Service 
public class HibernateSpringIntegrator {

private static final Logger log = LoggerFactory.getLogger(HibernateSpringIntegrator.class);

@Autowired
私有HibernateEntityManagerFactory entityManagerFactory;

@Autowired
私有HibernateSpringIntegratorRegistry hibernateSpringIntegratorRegistry;

@PostConstruct
public void registerListeners(){
log.debug(注册Spring管理的HibernateEventListeners);

EventListenerRegistry listenerRegistry =((SessionFactoryImpl)entityManagerFactory
.getSessionFactory())。getServiceRegistry()。getService(
EventListenerRegistry.class);
List< HibernateEventListener> eventListeners = hibernateSpringIntegratorRegistry
.getHibernateEventListeners(); (HibernateEventListener hel:eventListeners)
{
log.debug(Registering:{},hel.getClass());
if(PreInsertEventListener.class.isAssignableFrom(hel.getClass())){
listenerRegistry.appendListeners(EventType.PRE_INSERT,
(PreInsertEventListener)hel); (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

if(PostInsertEventListener.class.isAssignableFrom(hel.getClass())){
listenerRegistry.appendListeners(EventType.POST_INSERT,
(PostInsertEventListener)hel); (PostUpdateEventListener.class.isAssignableFrom(hel.getClass())){
listenerRegistry.appendListeners(EventType.POST_UPDATE,
(PostUpdateEventListener)hel);

if
}
if(PostDeleteEventListener.class.isAssignableFrom(hel.getClass())){
listenerRegistry.appendListeners(EventType.POST_DELETE,
(PostDeleteEventListener)hel);
}
//目前我们不需要其他类型的eventListeners。否则这种方法需要扩展。



code
$ b

注册表:

  @Component 
public class HibernateSpringIntegratorRegistry {

@Autowired(required = false)
private List< HibernateEventListener> hibernateEventListeners;

public List< HibernateEventListener> getHibernateEventListeners(){
if(hibernateEventListeners == null){
return Collections.emptyList();
}
返回hibernateEventListeners;




$ b $ p
$ b

下面是一个示例实现:

  @Component 
public class MailGenerationEventListener实现HibernateEventListener,
PostDeleteEventListener,PostInsertEventListener,PostUpdateEventListener {

@覆盖
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();
...
}
}


I'm used to using Spring to do my dependency injection like so:

<context:component-scan base-package="org.emmerich.myapp" />

and then annotating my dependent classes with Autowired like so:

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.

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.

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.

@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:

@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:

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.

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?

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:

@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. Here's the code:

The identifier interface for Spring managed Hibernate event listeners:

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();
        ...
    }
}

这篇关于使用Hibernate 4的Integrator模式和Spring的依赖注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆