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?
Lei non ha dimenticato di componente-scan 'MyIntegrator 'classe nel tuo esempio' @ Autowired'? Inoltre, chi sta creando un'istanza della classe 'MyIntegrator'? –
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. –
@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