Singleton Session Bean i Jakarta EE

1. Oversikt

Hver gang det kreves en enkelt forekomst av en sesjonsbønne for en gitt brukssak, kan vi bruke en Singleton sesjonsbønne.

I denne veiledningen skal vi utforske dette gjennom et eksempel, med en Jakarta EE-applikasjon.

2. Maven

Først og fremst må vi definere nødvendige Maven-avhengigheter i pom.xml.

La oss definere avhengighetene for EJB APIer og innebygd EJB-container for distribusjon av EJB:

 javax javaee-api 8.0 ga org.apache.openejb tomee-innebygd 1.7.5 

Siste versjoner finner du på Maven Central på JavaEE API og tomEE.

3. Typer øktbønner

Det er tre typer sesjonsbønner. Før vi utforsker Singleton Session Beans, la oss se hva som er forskjellen mellom livssyklusene til de tre typene.

3.1. Stateful Session Beans

En Stateful Session Bean opprettholder samtaletilstanden med klienten den kommuniserer.

Hver klient oppretter en ny forekomst av Stateful Bean og deles ikke med andre klienter.

Når kommunikasjonen mellom klienten og bønnen avsluttes, avsluttes også Session Bean.

3.2. Statsløse sesjonsbønner

En statsløs øktbønne opprettholder ingen samtalestatus med klienten. Bønnen inneholder tilstanden som er spesifikk for klienten, bare inntil metoden påkaller.

Fortløpende metodeinnkallelser er uavhengige i motsetning til Stateful Session Bean.

Containeren har et basseng av statsløse bønner, og disse forekomster kan deles mellom flere klienter.

3.3. Singleton Session Beans

En Singleton Session Bean opprettholder bønnens tilstand i hele applikasjonens livssyklus.

Singleton Session Beans ligner på Stateless Session Beans, men bare en forekomst av Singleton Session Bean opprettes i hele applikasjonen og avsluttes ikke før applikasjonen blir stengt.

Den eneste forekomsten av bønnen deles mellom flere klienter og kan nås samtidig.

4. Lage en Singleton Session Bean

La oss starte med å lage et grensesnitt for det.

For dette eksemplet, la oss bruke javax.ejb.Lokal kommentar for å definere grensesnittet:

@Lokalt offentlig grensesnitt CountryState {List getStates (strengland); ugyldige setStates (strengland, listestater); }

Ved hjelp av @Lokal betyr at bønnen er tilgjengelig i samme applikasjon. Vi har også muligheten til å bruke fjernkontroll kommentar som lar oss ringe EJB eksternt.

Nå skal vi definere implementering av EJB bønne klasse. Vi markerer klassen som en Singleton Session Bean ved å bruke merknaden javax.ejb.Singleton.

I tillegg, la oss også merke bønnen med javaxen.ejb.Startup kommentar for å informere EJB-beholderen om å initialisere bønnen ved oppstart:

@Singleton @ Startup offentlig klasse CountryStateContainerManagedBean implementerer CountryState {...}

Dette kalles ivrig initialisering. Hvis vi ikke bruker @Startup, bestemmer EJB-beholderen når bønnen skal initialiseres.

Vi kan også definere flere sesjonsbønner for å initialisere dataene og laste bønnene i den spesifikke rekkefølgen. Derfor bruker vi, javax.ejb.DependsOn kommentar for å definere vår bønnes avhengighet av andre sesjonsbønner.

Verdien for @Kommer an på kommentar er en matrise med navnene på Bean-klassenavn som Bean vår er avhengig av:

@Singleton @Startup @ DependsOn ({"DependentBean1", "DependentBean2"}) offentlig klasse CountryStateCacheBean implementerer CountryState {...}

Vi definerer en initialisere () metoden som initialiserer bønnen, og gjør den til en tilbakeringingsmetode for livssyklus ved hjelp av javax.annotation.PostConstruct kommentar.

Med denne merknaden vil den bli kalt av beholderen ved instantiering av bønnen:

@PostConstruct public void initialize () {List states = new ArrayList (); states.add ("Texas"); stater.add ("Alabama"); states.add ("Alaska"); states.add ("Arizona"); states.add ("Arkansas"); countryStatesMap.put ("UnitedStates", stater); }

5. Samtidighet

Deretter designer vi samtidig administrasjon av Singleton Session Bean. EJB tilbyr to metoder for å implementere samtidig tilgang til Singleton Session Bean: Container-managed concurrency og Bean-managed concurrency.

Kommentaren javax.ejb.ConcurrencyManagement definerer samtidighetspolitikken for en metode. Som standard bruker EJB-containeren containeradministrert samtidighet.

De @ConcurrencyManagement kommentar tar en javax.ejb.ConcurrencyManagementType verdi. Alternativene er:

  • ConcurrencyManagementType.CONTAINER for containerstyrt samtidighet.
  • ConcurrencyManagementType.BEAN for bønnestyrt samtidighet.

5.1. Container-Managed Concurrency

Enkelt sagt, i containeradministrert samtidighet, kontrollerer containeren hvordan klientenes tilgang til metoder.

La oss bruke @ConcurrencyManagement kommentar med verdi javax.ejb.ConcurrencyManagementType.CONTAINER:

@Singleton @Startup @ConcurrencyManagement (ConcurrencyManagementType.CONTAINER) offentlig klasse CountryStateContainerManagedBean implementerer CountryState {...}

For å spesifisere tilgangsnivået til hver av singletons forretningsmetoder bruker vi javax.ejb.Lås kommentar. javax.ejb.LockType inneholder verdiene for @Låse kommentar. javax.ejb.LockType definerer to verdier:

  • LockType.WRITE - Denne verdien gir en eksklusiv lås til den anropende klienten og forhindrer at alle andre klienter får tilgang til alle metodene til bønnen. Bruk dette til metoder som endrer tilstanden til singletonbønnen.
  • LockType.READDenne verdien gir samtidig lås til flere klienter for å få tilgang til en metode.

    Bruk dette til metoder som bare leser data fra bønnen.

Med dette i tankene vil vi definere setStates () metode med @Lock (LockType.WRITE) kommentar, for å forhindre samtidig oppdatering av staten av klienter.

For å tillate klienter å lese dataene samtidig, kommenterer vi getStates () med @Lock (LockType.READ):

@Singleton @Startup @ConcurrencyManagement (ConcurrencyManagementType.CONTAINER) offentlig klasse CountryStateContainerManagedBean implementerer CountryState {privat final Map

For å stoppe metodene som kjøres i lang tid og blokkere de andre klientene på ubestemt tid, bruker vi javax.ejb.AccessTimeout kommentar til timeout lang ventende samtaler.

Bruke @AccessTimeout kommentar for å definere antall millisekunder timeout-time. Etter tidsavbrudd kaster containeren a javax.ejb.ConcurrentAccessTimeoutException og metodeutførelsen avsluttes.

5.2. Bønnestyrt samtidighet

I Bean-administrert samtidighet kontrollerer ikke containeren samtidig tilgang til Singleton Session Bean av klienter. Utvikleren er pålagt å implementere samtidighet alene.

Med mindre samtidighet er implementert av utvikleren, er alle metoder tilgjengelige for alle klienter samtidig. Java tilbyr synkronisering og flyktige primitiver for å implementere samtidighet.

For å finne ut mer om samtidighet, les om java.util.concurrent her og Atomic Variables her.

For bønnestyrt samtidighet, la oss definere @ConcurrencyManagement kommentar med javax.ejb.ConcurrencyManagementType.BEAN verdi for Singleton Session Bean-klassen:

@Singleton @Startup @ConcurrencyManagement (ConcurrencyManagementType.BEAN) offentlig klasse CountryStateBeanManagedBean implementerer CountryState {...}

Deretter skriver vi setStates () metode som endrer tilstanden til bønnen ved hjelp av synkronisert nøkkelord:

offentlige synkroniserte ugyldige setStates (String land, Liste stater) {countryStatesMap.put (land, stater); }

De synkronisert nøkkelord gjør metoden tilgjengelig med bare en tråd om gangen.

De getStates () metoden endrer ikke tilstanden til Bean og så trenger den ikke å bruke synkronisert nøkkelord.

6. Oppdragsgiver

Nå kan vi skrive klienten for å få tilgang til Singleton Session Bean.

Vi kan distribuere Session Bean på applikasjonscontainerservere som JBoss, Glassfish etc. For å gjøre ting enkelt, vil vi bruke javax.ejb.embedded.EJBContainer klasse. EJBContainer kjører i samme JVM som klienten og gir de fleste tjenestene til en bedrifts bønnebeholder.

Først oppretter vi en forekomst av EJBContainer. Denne containerinstansen vil søke og initialisere alle EJB-modulene som er tilstede i klassestien:

offentlig klasse CountryStateCacheBeanTest {private EJBContainer ejbContainer = null; private Context context = null; @Før offentlig ugyldig init () {ejbContainer = EJBContainer.createEJBContainer (); kontekst = ejbContainer.getContext (); }}

Deretter får vi javax.naming.Context objekt fra det initialiserte containerobjektet. Bruker Kontekst for eksempel kan vi få referansen til CountryStateContainerManagedBean og kall metodene:

@Test offentlig ugyldig når CallGetStatesFromContainerManagedBean_ReturnsStatesForCountry () kaster unntak {String [] expectStates = {"Texas", "Alabama", "Alaska", "Arizona", "Arkansas"}; CountryState countryStateBean = (CountryState) kontekst .lookup ("java: global / singleton-ejb-bean / CountryStateContainerManagedBean"); Liste actualStates = countryStateBean.getStates ("UnitedStates"); assertNotNull (actualStates); assertArrayEquals (expectStates, actualStates.toArray ()); } @Test offentlig ugyldig når CallSetStatesFromContainerManagedBean_SetsStatesForCountry () kaster unntak {String [] expectStates = {"California", "Florida", "Hawaii", "Pennsylvania", "Michigan"}; CountryState countryStateBean = (CountryState) kontekst .lookup ("java: global / singleton-ejb-bean / CountryStateContainerManagedBean"); countryStateBean.setStates ("UnitedStates", Arrays.asList (expectedStates)); Liste actualStates = countryStateBean.getStates ("UnitedStates"); assertNotNull (actualStates); assertArrayEquals (expectStates, actualStates.toArray ()); }

På samme måte kan vi bruke Kontekst forekomst for å få referansen til Bean-Managed Singleton Bean og ringe de respektive metodene:

@Test offentlig ugyldig når CallGetStatesFromBeanManagedBean_ReturnsStatesForCountry () kaster unntak {String [] expectStates = {"Texas", "Alabama", "Alaska", "Arizona", "Arkansas"}; CountryState countryStateBean = (CountryState) kontekst .lookup ("java: global / singleton-ejb-bean / CountryStateBeanManagedBean"); Liste actualStates = countryStateBean.getStates ("UnitedStates"); assertNotNull (actualStates); assertArrayEquals (expectStates, actualStates.toArray ()); } @Test offentlig ugyldig når CallSetStatesFromBeanManagedBean_SetsStatesForCountry () kaster unntak {String [] expectStates = {"California", "Florida", "Hawaii", "Pennsylvania", "Michigan"}; CountryState countryStateBean = (CountryState) kontekst .lookup ("java: global / singleton-ejb-bean / CountryStateBeanManagedBean"); countryStateBean.setStates ("UnitedStates", Arrays.asList (expectedStates)); Liste actualStates = countryStateBean.getStates ("UnitedStates"); assertNotNull (actualStates); assertArrayEquals (expectStates, actualStates.toArray ()); }

Avslutt testene våre ved å lukke EJBContainer i Lukk() metode:

@Etter offentlig annullering lukk () {hvis (ejbContainer! = Null) {ejbContainer.close (); }}

7. Konklusjon

Singleton Session Beans er like fleksible og kraftige som alle standard Session Bean, men tillater oss å bruke et Singleton-mønster for å dele tilstand på tvers av applikasjonens klienter.

Samtidig styring av Singleton Bean kan enkelt implementeres ved hjelp av Container-Managed Concurrency hvor containeren tar seg av samtidig tilgang av flere kunder, eller du kan også implementere din egen tilpassede samtidighetsadministrasjon ved hjelp av Bean-Managed Concurrency.

Kildekoden til denne veiledningen finner du på GitHub.