Enterprise Java Beans (EJB) sind Komponenten für JEE-Application-Server. Ihre Methoden können sowohl von außerhalb ihres Application Servers als auch lokal aufgerufen werden.
EJBs unterscheiden sich in folgender Hinsicht:
- Session Bean: Dienen typischerweise einer Session und stellen diesen
Methoden zur Verfügung. Diese lassen sich weiter unterteilen:
- Stateful Session Bean
Die Klasse erhält die Annotation @Stateful.Die Daten der Bean bleiben in der Session erhalten und sind an diese gebunden. Typisches Beispiel ist ein Einkaufswagen bei einer Shopping-Anwendung.
- Statelesse Session Bean
Die Klasse erhält die Annotation @Stateless.Da die Bean kein Gedächtnis hat, kann der Application Server davon einen Pool anlegen, den er an die Aufrufer verteilt. Ein typisches Beispiel ist eine Bean zur Suche nach bestimmten Artikeln.
- Singleton Session Bean
Die Klasse erhält die Annotation @Singleton.Existiert genau ein Mal pro Application.
- Stateful Session Bean
- Enttity Bean: Sind Daten-Beans, die vor allem der Persistenz dienen. Siehe auch Java Persistance API (JPA). Sie werden durch die Annotation @Entity als solche deklariert und von einem EntityManager verwaltet.
- Message Driven Bean: Durch Messages des JMS angestoßene Bean. Das
JMS stellt zwei Arten von Queues zur Verfügung:
- Point to Point über eine QueueConnectionFactory
Der Sender legt eine Message in einer Warteschlange ab, die von der Message Driven Bean über einen Listener ausgelesen wird. - Publish and Subscribe über eine TopicConnectionFactory
Der Sender veröffentlicht an einer Warteschlange eine Nachricht mit einem Thema (Topic). Message Driven Beans können sich für Topics anmelden und werden informiert, wenn eine Nachricht zu ihrem Topic eingeht.
Eclipse erzeugt nach New | Message Driven Bean folgenden Programmrahmen:
@MessageDriven( activationConfig = { @ActivationConfigProperty( propertyName = "destinationType", propertyValue = "javax.jms.Queue") }) public class KundeMsgBean implements MessageListener { public KundeMsgBean() { } public void onMessage(Message message) { } }
- Point to Point über eine QueueConnectionFactory
Anlegen eines EJB-Server-Projekts
Mit Eclipse wird ein EJB-Projekt angelegt:- Aus dem Hauptmenü File | New | Other | EJB | EJB-Project, dann Next klicken.
- Der Projektname wird in der oberen Zeile eingegeben: EjbKunde
- Finish
- Klick mit der rechten Maus auf das Projekt EjbKunde
- Aus dem Kontextmenü New | Session Bean anklicken
- Der Eintrag für das Package muss gefüllt werden: kunde
- Class name: KundeEJB
- Remote anklicken, so dass der Haken sichtbar wird. Auf diese Weise erhält die Klasse die Annotation @Remote. Als Alternative steht Local zur Verfügung, das zu einer Annotation @Local führt.
- Finish
- Das Interface KundeEJBRemote.java:
In diesem Interface wird als Beispiel eine abstrakte Methode sagHallo eingetragen. Das Ergebnis sieht so aus:package kunde; import javax.ejb.Remote; @Remote public interface KundeEJBRemote { public String sagHallo(String name); }
- Die Klasse KundeEJB.java. Sie implementiert das Interface und
muss nun auch die abstrakte Methode implementieren:
package kunde; import javax.ejb.LocalBean; @Stateless @LocalBean public class KundeEJB implements KundeEJBRemote { public KundeEJB() { } @Override public String sagHallo(String name) { return "Hallo, " + name; } }
Das Projekt EJBKunde kann gestartet werden. Dazu wird es mit der rechten Maustaste angeklickt und Run | Run on Server ausgewählt.
Erzeugen eines Remote-Clients
Sie können eine EJB von einem normalen Java SE-Programm ansprechen. Allerdings muss dieses Programm einiges tun. So muss die Verbindung zum Server und dessen Broker geschlagen werden, um dann die Verbindung zur EJB zu finden.Unter Eclipse wird zunächst ein Client-Projekt angelegt:
- Aus dem Hauptmenü File | New | Project | Other | Java EE | Application Client, dann Next
- Als Name könnte beispielsweise EjbKundeClient verwendet werden.
- Finish
- Rechte Maustaste auf Projekt, Properies auswählen.
- In der linken Spalte Java Build Path auswählen.
- Auf der rechten Seite den Reiter Projects anklicken.
- Den Button Add anklicken.
- Aus den Projekten das Serverprojekt EjbKunde mit einem Haken versehen. Dann OK klicken.
- Den Dialog mit Apply and Close schließen.
Anbindung an den Glassfish
Für die Anbindung an den Glassfish wird dem Client die JAR-Datei gf-client.jar hinzugefügt. Sie befindet sich in der Glassfish-Installation unter dem Pfad glassfish/lib/gf-client.jar.Unter Eclipse kann diese Datei als externe JAR eingebunden, da sich die Installation des Glassfish wohl nicht ändern wird.
- Projekt mit rechter Maustaste anklicken und Properties wählen.
- In der linken Spalte Java Build Path anklicken.
- Auf der rechten Seite den Reiter Libraries anklicken.
- Den Button Add External JARs anklicken.
- Mit dem Dateiauswahl-Dialog nach glassfish/lib/gf-client.jar in der Glassfish-Installation suchen. Mit OK bestätigen.
- Dialog mit Apply and Close beenden.
JNDI: Java Name and Directory Interface
Der Cient erreicht die Verbindung zum Server über den Namensdiens Java Name and Directory Interface (JNDI). Dazu wird zunächst ein InitialContext angelegt, dessen Konstruktor eine Properties aufnimmt, über die der Server erreicht wird. Die Einträge für die Properties sind Glassfish-spezifisch.import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import kunde.KundeBeanRemote; public class Main { public static void main(String[] args) throws NamingException { new Main(); } public Main() throws NamingException { Properties verb = new Properties(); verb.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.enterprise.naming.SerialInitContextFactory"); verb.setProperty(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming"); verb.setProperty(Context.STATE_FACTORIES, "com.sun.corba.ee.imp.presentation.rmi.JNDIStateFactoryImpl"); verb.setProperty("org.omg.CORBA.ORBInitialHost", "localhost"); verb.setProperty("org.omg.CORBA.ORBInitialPort", "3700"); Context context = new InitialContext(verb); KundeBeanRemote kunde = (KundeBeanRemote) context.lookup( // ...Erst durch den Aufruf von lookup wird der Zugriff auf das Kundenobjekt im EJB möglich.
In Zeiten von SOAP und REST ist ein Aufruf einer EJB von einer Standalone-Anwendung eher ungewöhnlich.
Zeitgesteuerte Dienste
Der Application Server verfügt über einen Timer-Service. Um diesen zu nutzen, wird eine Stateless oder Singleton Session Bean angelegt. Unter Eclipse erfolgt dies in folgenden Schritten:- Das EJB-Projekt mit der rechten Maustaste anklicken.
- New | Other | EJB | Session Bean auswählen.
- Klick auf Next
- Im folgenden Dialog wird der Name der Bean eingegeben und ein Haken bei Stateless gesetzt.
Regelmäßig wiederholender Kurzzeit-Timer
Die Bean fügt den TimerService hinzu.Hinter der Annotation @PostConstruct wird die Methode implementiert, die nach dem Start der Bean laufen soll. Ein Konstruktor ist nicht interessant, weil dieser bereits bei Erstellung der Klasse startet.
Hier wird mit der Methode createTimer ein Timer aufgesetzt, der im Minutentakt regelmäßig die Time-Out-Methode aufruft. Der Start des Timers wird um eine Sekunde verzögert.
Mit der Annotation @TimeOut wird die Methode markiert, die durch den Timer ausgelöst wird. Der Name ist nicht so wichtig, wie der Parameter vom Typ Timer.
@Stateless @LocalBean public class TimerSessionEJB { @Resource private TimerService timerService; public TimerSessionEJB() { } @PostConstruct private void init() { timerService.createTimer(1000, 60*1000, "MeineTimerInformation"); } @Timeout public void execute(Timer timer) { System.out.println("Timer: " + timer.getInfo() // obiger String + timer.getNextTimeout() // nächstes Event (Date) + timer.getTimeRemaining()); // ms bis zum nächsten Event } }
Zeitversetzte Ausführung
Soll nur eine zeitversetzte Aktion erfolgen, verwendet man TimerConfig.@PostConstruct private void init() { TimerConfig timerConfig = new TimerConfig(); timerConfig.setInfo("MeineTimerInformation"); timerService.createSingleActionTimer(5*1000, timerConfig); }Auch hier wird die mit @TimeOut markierte Methode aufgerufen. Der Zeitversatz ist 5 Sekunden.
Scheduling nach Zeitplan
Ähnlich wie beim crontab unter UNIX und Linux kann die Annotation @Schedule eine Ausführung zu bestimmten Zeitpunkten auslösen.Unter Eclipse können Sie eine Bean mit einem @Schedule erzeugen, indem Sie New | Other | EJB | EJB Timer aus dem Kontextmenü des EJB-Projekts anklicken.
@Stateless public class TimerEJB { public TimerEJB() { } @SuppressWarnings("unused") @Schedule(second="*/10", minute="*", hour="8-23", dayOfWeek="Mon-Fri", dayOfMonth="*", month="*", year="*", info="MyTimer") private void scheduledTimeout(final Timer t) { System.out.println("@Schedule called at: " + new java.util.Date()); } }