Dove utilizzare EJB 3.1 e CDI?


120

Sto realizzando un prodotto basato su Java EE in cui sto utilizzando GlassFish 3 e EJB 3.1.

La mia applicazione ha bean di sessione , uno scheduler e utilizza servizi web. Recentemente sono venuto a conoscenza di Apache TomEE , che supporta Contexts and Dependency Injection (CDI) . Il contenitore GlassFish supporta anche CDI.

Posso sostituire i bean di sessione in cui non richiedo alcuna funzionalità che CDI non sia già fornita? E se poi, quali sono i vantaggi che posso ottenere?

Risposte:


408

Sì, puoi mescolare liberamente sia CDI che EJB e ottenere ottimi risultati. Sembra che tu stia usando @WebServicee @Schedule, che sono buone ragioni per aggiungere EJB al mix.

C'è molta confusione là fuori, quindi ecco alcune informazioni generali su EJB e CDI in quanto si riferiscono a ciascuno insieme.

EJB> = CDI

Notare che gli EJB sono bean CDI e quindi hanno tutti i vantaggi di CDI. Il contrario non è (ancora) vero. Quindi sicuramente non prendere l'abitudine di pensare "EJB vs CDI" poiché quella logica si traduce davvero in "EJB + CDI vs CDI", che è una strana equazione.

Nelle future versioni di Java EE continueremo ad allinearle. Cosa significa allineare sta permettendo alle persone di fare quello che già possono fare, basta senza la @Stateful, @Statelesso @Singletondi annotazione in alto.

EJB e CDI nei termini di implementazione

In definitiva, EJB e CDI condividono lo stesso design fondamentale di essere componenti proxy. Quando ottieni un riferimento a un bean EJB o CDI, non è il vero bean. Piuttosto l'oggetto che ti viene dato è un falso (un proxy). Quando si invoca un metodo su questo oggetto falso, la chiamata va al contenitore che invierà la chiamata tramite intercettori, decoratori, ecc., Oltre a occuparsi di qualsiasi transazione o controllo di sicurezza. Una volta fatto tutto ciò, la chiamata va finalmente all'oggetto reale e il risultato viene ritrasmesso al chiamante attraverso il proxy.

La differenza sta solo nel modo in cui viene risolto l'oggetto da richiamare. Per "risolto" intendiamo semplicemente dove e come il contenitore cerca l'istanza reale da invocare.

In CDI il contenitore guarda in un "ambito", che sarà fondamentalmente una hashmap che vive per un periodo di tempo specifico (per richiesta @RequestScoped, per sessione HTTP @SessionScoped, per applicazione @ApplicationScoped, conversazione JSF @ConversationScopedo per l'implementazione dell'ambito personalizzato).

In EJB il contenitore guarda anche in una hashmap se il bean è di tipo @Stateful. Un @Statefulbean può anche utilizzare una qualsiasi delle annotazioni dello scope sopra riportate facendolo vivere e morire con tutti gli altri bean nello scope. In EJB @Statefulè essenzialmente il bean "any scoped". L' @Statelessè fondamentalmente un pool di istanze - si ottiene un'istanza dal pool per la durata di un invocazione. Il @Singletonè essenzialmente@ApplicationScoped

Quindi, in un livello fondamentale, qualsiasi cosa tu possa fare con un bean "EJB" dovresti essere in grado di farlo con un bean "CDI". Sotto le coperte è terribilmente difficile distinguerli. Tutto l'impianto idraulico è lo stesso con l'eccezione di come vengono risolte le istanze.

Al momento non sono gli stessi in termini di servizi che il contenitore offrirà quando si esegue questo proxy, ma come ho detto ci stiamo lavorando a livello di specifica Java EE.

Nota sulle prestazioni

Ignora qualsiasi immagine mentale "leggera" o "pesante" che potresti avere. È tutto marketing. Hanno lo stesso design interno per la maggior parte. La risoluzione dell'istanza CDI è forse un po 'più complessa perché è leggermente più dinamica e contestuale. La risoluzione dell'istanza EJB è piuttosto statica, stupida e semplice al confronto.

Posso dirti da una prospettiva di implementazione in TomEE, c'è circa zero differenza di prestazioni tra invocare un EJB e invocare un bean CDI.

L'impostazione predefinita è POJO, quindi CDI, quindi EJB

Ovviamente non utilizzare CDI o EJB quando non ci sono vantaggi. Aggiungi CDI quando inizi a desiderare iniezione, eventi, intercettori, decoratori, monitoraggio del ciclo di vita e cose del genere. Quella è la maggior parte del tempo.

Al di là di queste basi, ci sono una serie di servizi utili container si ha solo la possibilità di utilizzare, se fate il vostro CDI fagiolo anche un EJB con l'aggiunta @Stateful, @Statelesso @Singletonsu di esso.

Ecco un breve elenco di quando rompo gli EJB.

Utilizzando JAX-WS

Esporre un JAX-WS @WebService. Sono pigro. Quando @WebServiceè anche un bean, non è necessario elencarlo e mapparlo come servlet nel web.xmlfile. Questo è lavoro per me. Inoltre ho la possibilità di utilizzare una qualsiasi delle altre funzionalità menzionate di seguito. Quindi è un gioco da ragazzi per me.

Disponibile @Statelesse @Singletonsolo.

Utilizzando JAX-RS

Esporre una risorsa JAX-RS tramite @Path. Sono ancora pigro. Quando il servizio RESTful è anche un EJB, di nuovo si ottiene il rilevamento automatico e non è necessario aggiungerlo a una Applicationsottoclasse JAX-RS o qualcosa del genere. Inoltre posso esporre lo stesso identico bean di un, @WebServicese lo desidero o utilizzare una delle fantastiche funzionalità menzionate di seguito.

Disponibile @Statelesse @Singletonsolo.

Logica di avvio

Carica all'avvio tramite @Startup. Attualmente non esiste un equivalente a questo in CDI. In qualche modo ci siamo persi l'aggiunta di qualcosa come un AfterStartupevento nel ciclo di vita del container. Se lo avessimo fatto, avresti semplicemente potuto avere un @ApplicationScopedbean che lo ascoltasse e che sarebbe effettivamente lo stesso di un @Singletoncon @Startup. È sulla lista per CDI 1.1.

Disponibile @Singletonsolo per.

Lavorare in parallelo

@Asynchronousinvocazione del metodo. L'avvio di thread è un no-no in qualsiasi ambiente lato server. Avere troppi thread è un serio killer delle prestazioni. Questa annotazione ti consente di parallelizzare le cose che fai usando il pool di thread del contenitore. Questo e spettacolare.

Disponibile per @Stateful, @Statelesse @Singleton.

Pianificazione del lavoro

@Scheduleo ScheduleExpressionè fondamentalmente un cron o una Quartzfunzionalità. Anche molto impressionante. La maggior parte dei contenitori usa solo Quartz sotto le coperte per questo. La maggior parte delle persone non sa, tuttavia, che il lavoro di pianificazione in Java EE è transazionale! Se aggiorni un database, pianifichi un lavoro e uno di essi non riesce, entrambi verranno automaticamente ripuliti. Se la EntityManagerchiamata persistente non riesce o si verifica un problema di scaricamento, non è necessario annullare la pianificazione del lavoro. Sì, transazioni.

Disponibile @Statelesse @Singletonsolo.

Utilizzo di EntityManagers in una transazione JTA

La nota sopra sulle transazioni ovviamente richiede di utilizzare un file JTAmanaged EntityManager. È possibile utilizzarli con un semplice "CDI", ma senza le transazioni gestite dal contenitore può diventare davvero monotono duplicare la UserTransactionlogica di commit / rollback.

Disponibile a tutti i componenti Java EE tra cui CDI, JSF @ManagedBean, @WebServlet, @WebListener, @WebFilter, ecc L' @TransactionAttributeannotazione, tuttavia, è a disposizione @Stateful, @Statelesse @Singletonsolo.

Mantenere JTA gestito EntityManager

Il EXTENDEDgestito EntityManagerconsente di mantenere EntityManageraperto tra le JTAtransazioni e di non perdere i dati memorizzati nella cache. Buona caratteristica per il momento e il luogo giusti. Usa responsabilmente :)

Disponibile @Statefulsolo per.

Facile sincronizzazione

Quando è necessaria la sincronizzazione, le annotazioni @Lock(READ)e @Lock(WRITE)sono piuttosto eccellenti. Ti consente di ottenere la gestione degli accessi simultanei gratuitamente. Salta tutti gli impianti idraulici ReentrantReadWriteLock. Nello stesso bucket c'è @AccessTimeout, che ti consente di dire quanto tempo un thread deve attendere per avere accesso all'istanza del bean prima di arrendersi.

Disponibile @Singletonsolo per i fagioli.


32
Santo cielo David :) Penso che tu l'abbia coperto.
LightGuard

7
Grazie per questa risposta. Hai cancellato lo zoccolo nella mia testa e collegato molti punti.
Thupten

7
Questa è di gran lunga la migliore spiegazione su questo argomento che abbia mai letto. Copre anche quasi tutti gli aspetti importanti di EJB nell'uso nella vita reale. Ottimo lavoro!!
nanoquack

3
Molto comprensibile e Adam non ha torto in termini strettamente legali, ma la distinzione è discutibile. La specifica dice che l'istanza EJB non è contestuale, ma poi dice che in seguito il riferimento (proxy) al EJB è contestuale. Il ciclo di vita di un bean stateful è controllato interamente tramite il riferimento (proxy), quindi quando il contenitore CDI controlla quel riferimento (proxy) la matematica risulta uguale: i bean Stateful possono essere effettivamente contestuali.
David Blevins

3
L'hai scritto durante la tua pausa pranzo al TESLA?
Edison

2

se davvero non stai usando nessuna delle funzionalità di ejb 3.1 la risposta è semplice. ma suppongo che la tua domanda indichi che sospetti che ci siano concetti di ejb 3.1 di cui stai beneficiando senza esserne a conoscenza. un esempio potrebbe essere che il contenitore può mantenere un pool di slsb pronto per essere utilizzato, in modo che jms e connessioni al database non debbano essere iniettati come parte della richiesta

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.