2013-04-15 10 views
7

Sono abituato ad usare primavera per fare la mia iniezione di dipendenza in questo modo:Usando modello di Hibernate 4 Integrator e l'iniezione di dipendenza di primavera

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

e quindi annotare le mie classi dipendenti con Autowired in questo modo:

public class DependentClass { 

    @Autowired 
    private Dependency dependency; 

} 

Tuttavia, con le modifiche in Hibernate 4.0, è ora consigliabile utilizzare la nuova interfaccia Integrator per l'individuazione dei servizi. Ciò include l'aggiunta di listener di eventi per trigger come postUpdate, postDelete ecc.

Sfortunatamente, questo non funziona bene con l'iniezione di dipendenza attraverso dipendenze annotate. Ho la seguente configurazione:

Un integratore che ho definito per aggiungere il mio listener allo ServiceFactory. Questo è indicato nel 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); 

} 

ho anche definito la classe MyListener, che si presenta come il tipico listener di eventi.

@Component 
public class MyListener implements PostInsertEventListener { 

    @Autowired 
    private Dependent dependent; 

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

} 

Unforunately, come mostrato dal commento, questo non funziona. Immagino che sia perché sto istanziando MyListener all'interno di MyIntegrator, non raccoglie il componente e non esegue la copia dei componenti. Tuttavia, se provo questo:

@Component 
public class MyIntegrator { 

    @Autowired 
    private MyListener listener; 

    ... 
} 

Quindi il listener non viene avviato automaticamente.

In primo luogo, sembra sbagliato quando si utilizza Spring per fare new MyListener(). Mi aspetto di essere in grado di definirlo come una dipendenza autowired e far sì che Spring crei un singleton per me. La mia domanda è questa:

Qual è l'approccio migliore all'utilizzo dell'iniezione di dipendenza con la nuova interfaccia Integrator? Gli integratori sono usati per costruire una SessionFactory, e così quando viene loro chiesto di integrarsi, credo che non ci sia un contesto applicativo disponibile. Per questo motivo, qualsiasi bean richiesto nell'Integrator deve essere creato in modo "vecchio stile" e non verrà visualizzato su di essi.

Sono abbastanza nuovo nel mondo di Primavera, diresti che è qualcosa che dovrei aspettarmi di vedere? Capisco che sono in un ambito diverso dell'applicazione quando sono in SessionFactory, ma c'è un modo per ottenere un riferimento al bean e abilitare autowire anche se lo sto creando tramite new?

La soluzione che ho trovato utilizzava ApplicationContextAware. Significava che MyListener riceveva un riferimento allo ApplicationContext ogni volta che il contesto era disponibile e facevo riferimento ai bean dal contesto sulle chiamate ai metodi, piuttosto che sulla costruzione dei bean. Creazione di un fagiolo con new non limita questo, così primavera mi dà ancora il contesto dell'applicazione:

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

} 

C'è un modo migliore?

+0

Lei non ha dimenticato di componente-scan 'MyIntegrator 'classe nel tuo esempio' @ Autowired'? Inoltre, chi sta creando un'istanza della classe 'MyIntegrator'? –

+0

Questa è esattamente la stessa soluzione che ho trovato anch'io. Funziona bene ma il contesto applicativo statico sembra un po 'sporco :) Non ho trovato un modo migliore perché l'ibernazione sta creando l'Integrator. Una volta che avrò tempo voglio renderlo più astratto e avere un integratore che è solo un link per poter registrare ascoltatori ecc. Creati dalla primavera. Ho trovato un blog una volta ma non riesco a ricordare l'url adesso. –

+1

@SotiriosDelimanolis Hibernate crea l'integratore per te. Specificate un file di testo nella vostra directory 'META-INF/services' che punta all'elenco di integratori che volete istanziato, e Hibernate li costruisce per voi prima di creare SessionFactory. In qualche modo capisco di non essere in grado di integrare i componenti di Autowire in Integrator: è costruito al di fuori dell'ambito dell'applicazione. Tuttavia, ho pensato che sarebbe stato possibile usare @Autowired nell'ascoltatore. E sì, sto contestando la scansione di tutte le classi coinvolte. – EMMERICH

risposta

12

Come indicato nel commento ho fatto un altro modo di integrare HibernateEventListeners gestito da Spring.Ecco il codice:

L'interfaccia identificatore per la primavera gestito Hibernate ascoltatori di eventi:

public interface HibernateEventListener { } 

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

Il "Registro di sistema":

@Component 
public class HibernateSpringIntegratorRegistry { 

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

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

Ed ecco un esempio di implementazione:

@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

Risposta interessante. È un'alternativa all'implementazione dell'interfaccia 'Integrator' e alla definizione del file di testo dell'integratore in' META-INF/services'? – EMMERICH

+0

Immagino che il problema che ho con questo è che non segue il pattern di Integrator, piuttosto fornisce un modo personalizzato Springified di allegare listener di eventi. – EMMERICH

+0

Sì, questa è un'implementazione completamente Springifed. Penso che si possa prendere il modo di implementare HibernateSpringIntegrator come servizio di integrazione "reale" usando ApplicationContextAware e recuperando HibernateSpringIntegratorRegistry. In questo modo l'integratore è in ibernazione come con un riferimento a applicationcontext statico ma è comunque in grado di utilizzare il semplice autowiring per gli eventlisteners attraverso il registro –

-1

Durante un aggiornamento da Hibernate 3,6-4,2, abbiamo bisogno di avere un validatore personalizzato che utilizza i fagioli di primavera gestiti nel modo seguente configurazione:

<!-- 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

Com'è rilevante? –

Problemi correlati