Spring ist ein modernes Baukastenframework, das als Alternative zum JEE-Stack entstand und für ähnliche Problemklassen eingesetzt wird. Üblicherweise werden Spring-Anwendungen auf Apache Tomcat ausgeliefert, was auch eine gute Idee ist. Versucht man nämlich, Spring auf einem vollwertigen JEE-Server einzusetzen, muss mit einigen Überraschungen gerechnet werden. Im Folgenden werden die Anpassungen beschrieben, die nötig sind, um eine Anwendung auf dem JBoss-Applikationsserver zum Laufen zu bringen.
Die Anwendung
Als Beispiel wird die folgende Anwendungskonfiguration verwendet:
- Spring 3.0
- JPA mit Hibernate 3.4.0 GA und MySQL 5.1.13
- Java Server Faces (JSF) 2.0.3
Die resultierende WAR-Datei ist 24MB groß und enthält vor allem ein paar Bibliotheken, die nicht ohne weiteres im JEE Server deployed werden dürfen.
Die Auslieferung
Damit die WAR-Datei überhaupt erfolgreich für einen JEE-Server ausgeliefert werden kann, müssen die folgenden JARs aus dem WAR entfernt werden:
- ejb3-persistence-1.0.2.GA.jar
- hibernate-annotations-3.4.0.GA.jar
- hibernate-commons-annotations-3.1.0.GA.jar
- hibernate-core-3.3.0.SP1.jar
- hibernate-entity-manager-3.4.0.GA.jar
- javassist-3.4.GA.jar
- jta-1.1.jar
- xml-apis.jar
- jsf-api-2.0.3.jar
- jsf-impl-2.0.3.jar
- el-api-2.0.3.b01.jar
- el-impl-2.0.3.b01.jar
- mysql-connector-java-5.1.13.jar
Hibernate-Bibliotheken dürfen nicht deployed werden, weil sie bereits Teil des JBoss AS sind und eventuell in anderer Version vorliegen. Daraus resultieren oft ClassCastExceptions
. Das Gleiche betrifft JTA, die ein Teil von JEE ist und XML-APIs, die zu ClassCastExceptions
bei Konfigurationsdateien führen. Die DB-Treiber sollten nicht innerhalb vom WAR deployed werden, wenn die Datasource im Server konfiguriert ist. Daher sollte der MySQL-Treiber ins /server/default/lib kopiert werden. Ein besonders komplizierter Eingriff ist aber notwendig, damit JSF 2.0 funktioniert. Ein JEE Server muss laut Spezifikation eine JSF-Unterstützung haben. JBoss AS 5 ist JEE-compliant und liefert JSF 1.2 als Implementierung mit aus. JSF 1.2 ist aber nicht binärkompatibel zu JSF 2.0, und deshalb müssen Teile vom JBoss ersetzt werden. In /server/default/deploy/jbossweb.sar/jsf-libs müssen JSF-JARs ersetzt werden. JSF 2.0 verwendet Expression Language 2.2, und so muss in /common/lib/ die vorhandene el-api.jar durch die neuere API samt Implemenetierung ersetzt werden. Als Ergebnis bleibt eine nur 12 MB große WAR-Datei, die deployed werden kann.
Die Konfiguration
Im Unterschied zu einer Apache Tomcat-Konfiguration, in der JPAs Persistence Unit im RESOURCE-LOCAL funktioniert, muss im JEE-Server der JTA-Modus verwendet werden. Dazu richtet man zunächst eine Datasource im JBoss Server ein (kopiert /docs/examples/jca/mysql-ds.xml ins /server/default/deploy) und ändert die Einstellungen entsprechend. Wichtig ist das jndi-name-Attribut (z.B. myDataSource). Als nächstes muss in der persistence.xml
die Konfiguration auf JTA umgeschaltet werden:
<persistence-unit name='myPU' transaction-type='JTA'> <jta-data-source>java:myDataSource</jta-data-source> <class>...</class> </persistence-unit>
Dann muss in der spring-config.xml
die Entity Manager Factory konfiguriert werden.
<bean id='entityManagerFactory' class='org.springframework.orm.jpa. LocalContainerEntityManagerFactoryBean'> <property name='jpaVendorAdapter'> <bean class='org.springframework.orm.jpa. vendor.HibernateJpaVendorAdapter'> <property name='showSql' value='true' /> <property name='generateDdl' value='true' /> <property name='databasePlatform' value='org.hibernate.dialect.MySQL5Dialect' /> </bean> </property> <property name='jpaProperties'> <props> <prop key='hibernate.transaction.factory_class'> org.hibernate.transaction.JTATransactionFactory </prop> <prop key='hibernate.transaction.manager_lookup_class'> org.hibernate.transaction.JBossTransactionManagerLookup </prop> </props> </property> </bean>
Als letztes muss die Datasource so konfiguriert werden, dass sie auf die Server-Datasource verweist und dass schließlich der Transaktionmanager, der von Spring verwendet wurde, zu der Entity Manager Factory passt.
<jee:jndi-lookup id='dataSource' jndi-name='java:myDataSource' cache='true' resource-ref='true' lookup-on-startup='true' proxy-interface='javax.sql.DataSource'/> <bean class='org.springframework.transaction.jta. JtaTransactionManager' id='transactionManager'/>
Fazit
So konfiguriert, funktioniert die Spring-Anwendung in einem JEE Server. Es sei jedoch die Frage erlaubt, warum man nicht gleich auf Spring verzichtet und mittels EJB 3.1 die Businesslogik implementiert. Schließlich wurde es genau dafür entwickelt und kommt mit deutlich weniger Konfiguration aus. Manchmal werden aber Rechnungen von Kunden bezahlt, die bereits eine Architekturauswahl getroffen haben und nicht mal eben auf EJB 3 umsteigen können.