2013-04-15 117 views
7

我已经习惯了使用Spring做我的依赖注入,像这样:使用Hibernate 4的集成模式和Spring的依赖注入

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

,然后标注我的依赖类与Autowired像这样:

public class DependentClass { 

    @Autowired 
    private Dependency dependency; 

} 

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

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

我已定义的集成商将我的收听者添加到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); 

} 

我也有定义的类MyListener,它看起来像典型的事件监听器。

@Component 
public class MyListener implements PostInsertEventListener { 

    @Autowired 
    private Dependent dependent; 

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

} 

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

@Component 
public class MyIntegrator { 

    @Autowired 
    private MyListener listener; 

    ... 
} 

然后,侦听器不是自动装配的。

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

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

我对春天的世界很陌生,你会说这是我应该期待看到的东西吗?我知道当我在SessionFactory中时,我处于应用程序的不同范围中,但是有没有办法获得对bean的引用并启用自动装配,即使我通过new创建它?

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

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

} 

有没有更好的办法?

+0

你没忘了组件扫描'MyIntegrator '你的'@ Autowired'例子中的类?另外,谁正在实例化MyIntegrator类? –

+0

这也是我提出的完全相同的解决方案。它的工作很好,但静态applicationcontext只是觉得有点肮脏:)我只是没有找到一个更好的方式,因为休眠创建集成器。一旦我有时间,我想让这个更抽象,并有一个集成商,这只是一个链接,可以注册春天创建的监听器等。我发现了一次博客,但我现在不记得这个网址。 –

+1

@SotiriosDelimanolis Hibernate为你创建'Integrator'。您可以在META-INF/services目录中指定一个文本文件,指向您要实例化的集成器列表,Hibernate会在创建SessionFactory之前为您创建它们。我有点理解无法在Integrator中使用Autowire组件 - 它是在应用程序范围之外构建的。不过,我认为可以在侦听器中使用@Autowired。是的,我在上下文中扫描涉及的所有类。 – EMMERICH

回答

12

正如在评论中所说,我去另一种方式集成Spring管理HibernateEventListeners。下面的代码:

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

public interface HibernateEventListener { } 

的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. 
     } 
    } 
} 

“注册表”:

@Component 
public class HibernateSpringIntegratorRegistry { 

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

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

这里是一个示例实现:

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

有趣的回应。这是否可以替代实现'Integrator'接口并在'META-INF/services'中定义集成商文本文件? – EMMERICH

+0

我想我遇到的问题是它不遵循集成器模式,而是它提供了一种自定义的附加事件侦听器的Spring化方法。 – EMMERICH

+0

是的,这是一个完整的Springifed实现。我认为可以通过使用ApplicationContextAware并获取HibernateSpringIntegratorRegistry来实现HibernateSpringIntegrator作为“真正”集成服务的方式。通过这种方式,集成者像Hibernate一样具有静态的应用程序上下文引用,但仍然能够通过注册表 –

-1

在从休眠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> 
+0

这是如何相关? –