2010-03-08 8 views
6

Abbiamo un bean EJB stateless JavaEE5 che passa EntityManager iniettato ai relativi helper.Va bene passare EntityManager iniettati alle classi helper del bean EJB e usarlo?

È sicuro? Ha funzionato bene fino ad ora, ma ho scoperto alcuni documenti Oracle che affermano che la sua implementazione di EntityManager è thread-safe. Ora mi chiedo se il motivo per cui non abbiamo avuto problemi fino ad ora, fosse solo perché l'implementazione che stavamo usando si è rivelata thread-safe (usiamo Oracle).

@Stateless 
class SomeBean { 
    @PersistenceContext 
    private EntityManager em; 

    private SomeHelper helper; 

    @PostConstruct 
    public void init(){ 
     helper = new SomeHelper(em); 
    } 

    @Override 
    public void business(){ 
     helper.doSomethingWithEm(); 
    } 

} 

In realtà ha senso .. Se EntityManager è thread-non sicuro, un contenitore avrebbe dovuto fare

inercept business() 
this.em = newEntityManager(); 
business(); 

che non propagano alle sue classi helper.

Se sì, qual è la migliore pratica in questo tipo di situazione? Passare EntityManagerFactory invece di EntityManager?

EDIT: This question è molto interessante, quindi se siete interessati a questa domanda, probabilmente si desidera controllare anche questa:

EDIT: Maggiori informazioni. istanze ejb3.0 spec

4.7.11 non-rientranti Il contenitore deve assicurare che un solo thread può essere in esecuzione un'istanza in qualsiasi momento. Se una richiesta di un cliente arriva a per un'istanza mentre l'istanza è in esecuzione un'altra richiesta, il contenitore può lanciare il javax.ejb.ConcurrentAccessException a il secondo client [24]. Se viene utilizzata la vista client EJB 2.1 , il contenitore può gettare il java.rmi.RemoteException per seconda richiesta se il cliente è un client remoto, oppure il javax.ejb.EJBException se il client è un locale cliente. [25] Si noti che un oggetto di sessione è destinato a supportare solo un singolo client. Pertanto, è un errore dell'applicazione se due client hanno tentato di richiamare lo stesso oggetto di sessione . Un'implicazione di è che un'applicazione non può effettuare chiamate di loopback a un'istanza di bean di sessione .

E,

4.3.2 Dependency Injection un session bean può utilizzare l'iniezione di dipendenza meccanismi per acquisire riferimenti a risorse o altri oggetti nel suo ambiente (si veda il Capitolo 16, "Enterprise Bean Environment"). Se un chicco sessione si avvale di dipendenza iniezione, il contenitore inietta queste riferimenti dopo l'istanza di bean è creato, e prima di qualsiasi attività commerciale metodi vengono richiamati sul fagiolo istanza.Se viene dichiarata una dipendenza dal SessionContext o se la classe bean implementa l'interfaccia SessionBean opzionale (vedere la Sezione 4.3.5), al momento viene iniettata anche SessionContext. Se l'iniezione della dipendenza non riesce, l'istanza del bean è scartata. Sotto l'API EJB 3.0, la classe bean può acquisire l'interfaccia SessionContext tramite l'integrazione delle dipendenze senza dover implementare l'interfaccia SessionBean con . In questo caso, l'annotazione della risorsa (o elemento descrittore risorsa-env-ref ) viene utilizzata per indicare la dipendenza del bean da sul SessionContext . Vedi Capitolo 16, "Ambiente Bean Enterprise".

+0

Ora questo è interessante "La specifica EJB 3.1 afferma che l'iniezione di dipendenza viene eseguita solo in fase di costruzione, in modo che tutti i chiamanti di MyRepository utilizzino la stessa istanza di EntityManager." : http: //stackoverflow.com/questions/2015184/how-is-threadsafty-guranted-with-persistencecontext –

+0

FYI, leggi anche § 4.1.13, o vedi questa risposta http: // stackoverflow.com/domande/1954137/come-è-che-esempio-pooling-con-EJB-can-migliorare le prestazioni/1.954.229 # 1.954.229. Quindi a ciascun aiutante sarà possibile accedere da un thread alla volta. – ewernli

+0

Questo è esattamente lo schema che stavo pensando di implementare. Sono molto felice di vedere che è possibile. Ottimo post. Grazie. – b3bop

risposta

2

Ho utilizzato uno schema simile, ma l'helper è stato creato in @PostConstruct e il gestore entità inserito è stato passato nel costruttore come parametro. Ogni istanza EJB aveva il proprio helper e la sicurezza del thread era garantita.

Avevo anche una variante in cui il gestore dell'entità non era stato iniettato (perché l'EJB non lo utilizzava del tutto), quindi l'helper deve cercarlo con InitialContext. In questo caso, il contesto di persistenza deve comunque essere "importata" nel EJB genitore con @PersistenceContext:

@Stateless 
@PersistenceContext(name="OrderEM") 
public class MySessionBean implements MyInterface { 
    @Resource SessionContext ctx; 
    public void doSomething() { 
    EntityManager em = (EntityManager)ctx.lookup("OrderEM"); 
    ... 
    } 
} 

ma in realtà è più facile da iniettare (anche se l'EJB non lo usa) che guardare in su , soprattutto per testabilità.

Ma per tornare alla domanda principale, penso che il gestore di entità che viene iniettato o cercato sia un wrapper che inoltra al gestore di entità attivo sottostante associato alla transazione.

Spero che aiuti.

EDIT

La sezione § 3.3 e § 5.6 nelle specifiche coprire un po 'l'argomento.

+0

Grazie, mi fa piacere sapere che non dobbiamo scavare nel nostro codice di produzione! –

2

Sto usando aiutante metodi e superato l'EntityManager lì, ed è perfettamente OK.

Quindi suggerirei di passarlo ai metodi ogni volta che è necessario, o rendere l'helper un bean stesso, iniettarlo (usando @EJB) e iniettare anche lo EntityManager.

+0

I metodi di supporto sembrano davvero semplici e validi. Grazie! –

0

Bene, personalmente, non mi piacerebbe dover passare l'Entity Manager a tutti i miei POJO nei miei costruttori o metodi. Soprattutto per i programmi non banali in cui il numero di POJO è grande.

Vorrei provare a creare POJO/HelperClass che gestiscono le Entità restituite da EntityManager, invece di utilizzare direttamente il gestore di entità.

Se non fosse possibile, credo che creerei un nuovo bean EJB.