Webentwicklung im Licht von Java EE Profiles und "EJB Lite"
Seite 3: EJB, JSF und JPA
EJB und JSF – a perfect match?
Der Zugriff von Managed Beans auf EJBs und andere Managed-Ressourcen von "Java EE"-Containern gestaltet sich dann erwartungsgemäß recht einfach. Das JSF-Framework unterstützt die vom EJB-Container bekannten Annotationen @EJB
und @Resource
, sodass sich, wie im folgenden Beispiel zu sehen, ohne große Klimmzüge die Brücke vom Web zum EJB-Container schlagen lässt:
@ManagedBean
public class WeblogBean {
@EJB
private WeblogService service;
}
Der Nutzung von EJBs und JPA in einer Webanwendung steht damit nichts mehr im Wege. Doch halt: Musste man EJBs bisher nicht in einem eigenen.jar
-Archiv ausrollen, sodass man beim Einsatz von EJBs neben dem .war
-Webarchiv noch ein weiteres EJB-Archiv benötigte? In der Tat besteht die Einschränkung – bis Java EE 5. Ab der neuen Version lassen sich EJBs direkt mit dem Webarchiv deployen. Das Schlüsselwort dazu heißt EJB 3.1 Lite und besagt, dass ausgewählte Funktionen der EJBs auch innerhalb von Webanwendung unterstützt werden. Insbesondere handelt es sich um lokale Stateful-, Stateless- und Singleton Session Beans mit oder ohne explizites Business-Interface (siehe dazu auch Artikel zwei der Serie). Message Driven Beans, Asynchronous Invocations und EJB 2.x/1.x Entity Beans unterstützt die Lite-Variante hingegen nicht, was sicherlich für eine große Anzahl Webanwendungen zu verschmerzen ist.
Designlücke JPA-Integration
In Summe hinterlässt die JSF-EJB-Integration einen runden Eindruck – zumindest auf dem Papier. Möchte man aber persistente Objekte, die die Java Persistence API verwaltet, innerhalb von JSF Views nutzen, stößt man unweigerlich auf ein erhebliches Designproblem. Ohne an der Stelle zu tief in Details gehen zu wollen: Irgendwie scheinen die Designer der Integration von JSF, EJB und JPA übersehen zu haben, dass die Lebenszeit des sogenannten JPA-EntityManagers, der die Interaktion mit der Datenbank koordiniert, in der Regel an eine Transaktion gebunden ist. So lange also eine Transaktion existiert, so lange lebt auch der EntityManager. Wird die Transaktion beendet, wird auch der EntityManager geschlossen.
Dummerweise kann nun eine normale JSF Managed Bean nicht ohne Weiteres Transaktionen selbst verwalten, sodass beim Verwenden von EJB und JPA unweigerlich das Transaktionsmanagement auf der Ebene der EJB-Methoden erfolgen muss. Zu tief, wenn man zum Beispiel die positiven Caching-Aspekte und das Lazy Loading des EntityManager im View nutzen möchte. (Die Möglichkeit, Transaktionen in einer JSF Managed Bean manuell zu verwalten, sollte dabei als keine wartbare Alternative angesehen werden.)
Leider gibt es aus dem Standard heraus keine einfache und saubere Lösung dieses Problems, es sei denn, man setzt wie JBoss Seam auf Stateful Sessions Beans oder auf das Spring Framework. Oder aber man verzichtet gänzlich auf EJBs und nutzt eine Technik, die praktisch in letzter Minute in die "Java EE 6"-Plattform aufgenommen wurde.