Singleton Session Bean i Jakarta EE

1. Oversigt

Når der kræves en enkelt forekomst af en Session Bean til en given brugssag, kan vi bruge en Singleton Session Bean.

I denne vejledning skal vi udforske dette gennem et eksempel med en Jakarta EE-applikation.

2. Maven

Først og fremmest skal vi definere krævede Maven-afhængigheder i pom.xml.

Lad os definere afhængighederne for EJB API'erne og den indlejrede EJB-container til implementering af EJB:

 javax javaee-api 8.0 leverede org.apache.openejb tomee-integreret 1.7.5 

Seneste versioner findes på Maven Central på JavaEE API og tomEE.

3. Typer af sessionbønner

Der er tre typer sessionbønner. Før vi udforsker Singleton Session Beans, lad os se, hvad der er forskellen mellem livscyklussen af ​​de tre typer.

3.1. Stateful Session Beans

En Stateful Session Bean opretholder samtaletilstanden med den klient, den kommunikerer.

Hver klient opretter en ny forekomst af Stateful Bean og deles ikke med andre klienter.

Når kommunikationen mellem klienten og bønnen slutter, afsluttes også Session Bean.

3.2. Statsløse sessionbønner

En statsløs session bønne opretholder ikke nogen samtaletilstand med klienten. Bønnen indeholder kun den specifikke tilstand for klienten indtil varigheden af ​​metodeopkald.

På hinanden følgende metodeindkaldelser er uafhængige i modsætning til Stateful Session Bean.

Containeren vedligeholder en pulje af statsløse bønner, og disse forekomster kan deles mellem flere klienter.

3.3. Singleton Session Beans

En Singleton Session Bean opretholder bønnens tilstand i applikationens hele livscyklus.

Singleton Session Beans svarer til Stateless Session Beans, men kun en forekomst af Singleton Session Bean oprettes i hele applikationen og afsluttes ikke, før applikationen lukkes ned.

Den eneste forekomst af bønnen deles mellem flere klienter og kan tilgås samtidigt.

4. Oprettelse af en Singleton Session Bean

Lad os starte med at oprette en grænseflade til den.

Lad os i dette eksempel bruge javax.ejb.Lokal kommentar til at definere grænsefladen:

@Lokal offentlig grænseflade CountryState {Liste getStates (strengland); ugyldige setStates (land i streng, liste stater); }

Ved brug af @Lokal betyder, at der er adgang til bønnen i samme applikation. Vi har også mulighed for at bruge javax.ejb. fjernbetjening kommentar, som giver os mulighed for at ringe til EJB eksternt.

Nu definerer vi implementering af EJB-bønneklassen. Vi markerer klassen som en Singleton Session Bean ved hjælp af annotation javax.ejb.Singleton.

Lad os desuden markere bønnen med javaxen.ejb.Startup kommentar for at informere EJB-containeren om at initialisere bønnen ved opstart:

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

Dette kaldes ivrig initialisering. Hvis vi ikke bruger @Start op, bestemmer EJB-beholderen, hvornår bønnen skal initialiseres.

Vi kan også definere flere sessionbønner for at initialisere dataene og indlæse bønnerne i den specifikke rækkefølge. Derfor bruger vi, javax.ejb.DependsOn kommentar til at definere vores bønnes afhængighed af andre sessionbønner.

Værdien for @Afhænger af annotation er en matrix med navnene på Bean-klassenavne, som vores Bean afhænger af:

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

Vi definerer en initialisere () metode, der initialiserer bønnen og gør den til en livscyklus-tilbagekaldningsmetode ved hjælp af javax.annotation.PostConstruct kommentar.

Med denne kommentar kaldes den af ​​beholderen ved instantiering af 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. Samtidighed

Dernæst designer vi samtidighedsstyringen af ​​Singleton Session Bean. EJB giver to metoder til implementering af samtidig adgang til Singleton Session Bean: Container-managed concurrency og Bean-managed concurrency.

Annotationen javax.ejb.ConcurrencyManagement definerer samtidighedspolitikken for en metode. Som standard bruger EJB-containeren containeradministreret samtidighed.

Det @ConcurrencyManagement annotering tager en javax.ejb.ConcurrencyManagementType værdi. Mulighederne er:

  • ConcurrencyManagementType.CONTAINER for containeradministreret samtidighed.
  • ConcurrencyManagementType.BEAN for bønnestyret samtidighed.

5.1. Containeradministreret samtidighed

Kort sagt, i containeradministreret samtidighed, kontrollerer containeren, hvordan klienters adgang til metoder.

Lad os bruge @ConcurrencyManagement kommentar med værdi javax.ejb.ConcurrencyManagementType.CONTAINER:

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

For at specificere adgangsniveauet til hver af singletons forretningsmetoder bruger vi javax.ejb.Lås kommentar. javax.ejb.LockType indeholder værdierne for @Låse kommentar. javax.ejb.LockType definerer to værdier:

  • LockType.WRITE - Denne værdi giver en eksklusiv lås til den opkaldende klient og forhindrer alle andre klienter i at få adgang til alle metoder til bønnen. Brug dette til metoder, der ændrer tilstanden for singletonbønnen.
  • LockType.READDenne værdi giver samtidige låse til flere klienter for at få adgang til en metode.

    Brug dette til metoder, der kun læser data fra bønnen.

Med dette i tankerne definerer vi setStates () metode med @Lock (LockType.WRITE) kommentar for at forhindre samtidig opdatering af staten af ​​klienter.

For at give klienter mulighed for at læse dataene samtidigt, kommenterer vi getStates () med @Lock (LockType.READ):

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

For at stoppe de metoder, der udføres i lang tid og blokere de andre klienter på ubestemt tid, bruger vi javax.ejb.AccessTimeout kommentar til timeout for langvarige opkald.

Brug @AccessTimeout annotation for at definere antallet af millisekunder timeout-time. Efter timeout'en kaster containeren a javax.ejb.ConcurrentAccessTimeoutException og metodeudførelsen afsluttes.

5.2. Bønnestyret samtidighed

I Bean-administreret samtidighed kontrollerer containeren ikke samtidig adgang til Singleton Session Bean af klienter. Udvikleren skal selv implementere samtidighed.

Medmindre samtidighed implementeres af udvikleren, er alle metoder tilgængelige for alle klienter samtidigt. Java leverer synkronisering og flygtige primitiver til implementering af samtidighed.

For at finde ud af mere om samtidighed, læs om java.util.concurrent her og Atomic Variables her.

For bønnestyret samtidighed, lad os definere @ConcurrencyManagement kommentar med javax.ejb.ConcurrencyManagementType.BEAN værdi for Singleton Session Bean-klassen:

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

Dernæst skriver vi setStates () metode, der ændrer bønnens tilstand ved hjælp af synkroniseret nøgleord:

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

Det synkroniseret nøgleord gør metoden tilgængelig med kun en tråd ad gangen.

Det getStates () metode ændrer ikke tilstanden for Bean, og det behøver derfor ikke at bruge synkroniseret nøgleord.

6. Klient

Nu kan vi skrive klienten for at få adgang til vores Singleton Session Bean.

Vi kan implementere Session Bean på applikationscontainerservere som JBoss, Glassfish osv. For at holde tingene enkle bruger vi javax.ejb.embedded.EJBContainer klasse. EJBContainer kører i samme JVM som klienten og leverer de fleste tjenester i en virksomheds bønnecontainer.

Først opretter vi en forekomst af EJBContainer. Denne containerinstans søger og initialiserer alle de EJB-moduler, der findes på klassestien:

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

Derefter får vi javax.naming.Context objekt fra det initialiserede containerobjekt. Bruger Sammenhæng eksempel kan vi få henvisningen til CountryStateContainerManagedBean og kalde metoderne:

@Test offentlig ugyldig når CallGetStatesFromContainerManagedBean_ReturnsStatesForCountry () kaster undtagelse {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 ()); } Offentligt @ @ test når CallSetStatesFromContainerManagedBean_SetsStatesForCountry () kaster undtagelse {String [] expectStates = {"Californien", "Florida", "Hawaii", "Pennsylvania", "Michigan"}; CountryState countryStateBean = (CountryState) kontekst .lookup ("java: global / singleton-ejb-bean / CountryStateContainerManagedBean"); countryStateBean.setStates ("UnitedStates", Arrays.asList (expectStates)); Vis faktiskStates = countryStateBean.getStates ("UnitedStates"); assertNotNull (actualStates); assertArrayEquals (expectStates, actualStates.toArray ()); }

På samme måde kan vi bruge Sammenhæng eksempel for at få referencen til Bean-Managed Singleton Bean og kalde de respektive metoder:

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

Afslut vores tests ved at lukke EJBContainer i tæt() metode:

@Efter offentligt ugyldigt tæt () {hvis (ejbContainer! = Null) {ejbContainer.close (); }}

7. Konklusion

Singleton Session Beans er lige så fleksible og kraftfulde som enhver standard Session Bean, men tillader os at anvende et Singleton-mønster for at dele tilstand på tværs af vores applikations klienter.

Samtidig styring af Singleton Bean kan let implementeres ved hjælp af Container-Managed Concurrency, hvor containeren sørger for samtidig adgang fra flere klienter, eller du kan også implementere din egen brugerdefinerede samtidighedsstyring ved hjælp af Bean-Managed Concurrency.

Kildekoden til denne vejledning kan findes på GitHub.