4. Voorbeeldapplicatie – 02: rdvmedecins-jsf2-spring
We gaan nu de vorige applicatie overzetten naar een Spring/Tomcat-omgeving:
![]() |
Het gaat hier daadwerkelijk om een port. We gaan uit van de vorige applicatie en passen deze aan de nieuwe omgeving aan. We zullen alleen de wijzigingen toelichten. Deze zijn van drie soorten:
- de server is niet langer Glassfish maar Tomcat, een lichte server zonder container EJB,
- ter vervanging van de EJB gebruiken we Spring, de belangrijkste concurrent van de EJB en [http://www.springsource.com/],
- de implementatie JPA die we zullen gebruiken is Hibernate in plaats van EclipseLink.
Omdat we veel zullen kopiëren en plakken tussen het oude en het nieuwe project, houden we de eerdere projecten open in NetBeans:
![]() |
Het gebruik van het Spring-framework vereist bepaalde kennis die te vinden is in [ref7] (zie pagina 166).
4.1. De lagen [DAO] en [JPA]
![]() |
4.1.1. Het NetBeans-project
We bouwen een Maven-project van het type [Java Application]:
![]() | ![]() | ![]() |
![]() |
- in [1], het aangemaakte project,
- in [2], hetzelfde project zonder de pakketten van [Source Packages] en [Test Packages] en zonder de afhankelijkheid [junit-3.8.1].
Het moeilijkste aan Maven-projecten is het vinden van de juiste afhankelijkheden. Voor dit Spring-/JPA-/Hibernate-project zijn dat de volgende:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>istia.st</groupId>
<artifactId>mv-rdvmedecins-spring-dao-jpa</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>mv-rdvmedecins-spring-dao-jpa</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.1.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.hibernate.java-persistence</groupId>
<artifactId>jpa-api</artifactId>
<version>2.0.Beta-20090815</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.1.1.RELEASE</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.1.1.RELEASE</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.1.1.RELEASE</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.1.1.RELEASE</version>
<type>jar</type>
</dependency>
</dependencies>
</project>
- regels 18-29: voor Hibernate,
- regels 30-34: voor de driver JDBC van MySQL,
- regels 35-41: voor de test JUnit,
- regels 42-51: voor de Apache Commons-verbindingspool DBCP. Een verbindingspool is een verzameling geopende verbindingen. Wanneer de applicatie een verbinding nodig heeft, vraagt deze deze aan bij de pool. Wanneer de applicatie de verbinding niet meer nodig heeft, geeft deze deze terug. De verbindingen worden bij het opstarten van de applicatie geopend en blijven gedurende de hele levensduur van de applicatie open. Dit voorkomt de kosten van herhaaldelijk openen en sluiten van verbindingen. Dit type pool bestond al in Glassfish, maar het gebruik ervan was voor ons transparant. Dat zal hier ook het geval zijn, maar we moeten het wel installeren en configureren,
- regels 52-75: voor Spring.
Laten we deze afhankelijkheden toevoegen en het project bouwen:
![]() |
- in [1]; door het project te bouwen, wordt Maven gedwongen de afhankelijkheden te downloaden,
- in [2] verschijnen deze vervolgens in de branch [Dependencies]. Het zijn er heel veel, aangezien de frameworks Hibernate en Spring zelf ook heel veel afhankelijkheden hebben. Ook hier hoeven we ons dankzij Maven geen zorgen te maken over deze afhankelijkheden. Ze worden automatisch gedownload.
Nu we de afhankelijkheden hebben, plakken we de code van het project EJB uit de laag [dao] in het Spring-project van de laag [dao]:
![]() |
- in [1], we kopiëren naar het bronproject,
- in [2], plakken we het in het doelproject,
- in [3], het resultaat.
Zodra het kopiëren is voltooid, moeten de fouten worden gecorrigeerd.
4.1.2. Het pakket [exceptions]
![]() |
De klasse [RdvMedecinsExceptions] [1] bevat fouten vanwege het pakket [javax] op regel 4, dat niet meer bestaat. Dit is een pakket dat specifiek is voor EJB. De fout op regel 6 vloeit voort uit die op regel 4. We verwijderen deze twee regels. Hierdoor worden de fouten in [2] verholpen.
4.1.3. Het pakket [jpa]
![]() |
- in [1] is de klasse [Creneau] onjuist vanwege het ontbreken van het validatiepakket van de regel [5]. We hadden dit pakket aan de afhankelijkheden van het project kunnen toevoegen. Maar tijdens het testen genereert Hibernate hierdoor een uitzondering. Aangezien het niet essentieel is voor onze applicatie, hebben we het verwijderd. Om de klasse te corrigeren, volstaat het om alle foutieve regels [2] te verwijderen. Dit doen we voor alle foutieve klassen.
4.1.4. Het pakket [dao]
We zijn nu bij het volgende punt aangekomen:
![]() |
- in [1], de twee gecorrigeerde pakketten,
- in [2], het pakket [dao]. Aangezien er geen EJB meer is, bestaat ook het begrip ‘externe en lokale interface’ van EJB niet meer. We verwijderen ze: [3].
![]() |
- In [1] hebben de fouten van de klasse [DaoJpa] twee oorzaken:
- het importeren van een pakket dat gekoppeld is aan EJB (regels 6-8);
- het gebruik van de lokale en externe interfaces die we zojuist hebben verwijderd.
We verwijderen de foutieve regels en gebruiken de interface [IDao] in plaats van de lokale en externe interfaces [2].
![]() |
In het project EJB was de klasse [DaoJpa] een singleton en werden de methoden ervan binnen een transactie uitgevoerd. We zullen zien dat de klasse [DaoJpa] een door Spring beheerde bean wordt. Standaard is elke Spring-bean een singleton. Tot zover de eerste eigenschap. De tweede eigenschap wordt verkregen met de Spring-annotatie @Transactional [3]:
![]() |
Nu dit is gebeurd, vertoont het project geen fouten meer [4].
4.1.5. Configuratie van de laag [JPA]
In het project EJB hadden we de laag [JPA] geconfigureerd met het bestand [persistence.xml]. Hier hebben we een laag [JPA] en dus moeten we dit bestand aanmaken. In het project EJB hadden we het met Glassfish gegenereerd. Hier bouwen we het handmatig op. De belangrijkste reden hiervoor is dat een deel van de configuratie van het bestand [persistence.xml] wordt overgeheveld naar het Spring-configuratiebestand zelf.
We maken het bestand [persistence.xml] aan:
![]() |
met de volgende inhoud:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="spring-dao-jpa-hibernate-mysqlPU" transaction-type="RESOURCE_LOCAL">
<class>rdvmedecins.jpa.Client</class>
<class>rdvmedecins.jpa.Creneau</class>
<class>rdvmedecins.jpa.Medecin</class>
<class>rdvmedecins.jpa.Rv</class>
</persistence-unit>
</persistence>
- regel 3: we geven de persistentie-eenheid een naam,
- regel 3: het transactietype is RESOURCE_LOCAL. In het project EJB was dit JTA om aan te geven dat de transacties werden beheerd door de container EJB. De waarde RESOURCE_LOCAL geeft aan dat de applicatie haar transacties zelf beheert. Dat gebeurt hier via Spring,
- regels 4-7: de volledige namen van de vier entiteiten JPA. Dit is optioneel, omdat Hibernate ze automatisch opzoekt in de ClassPath van het project.
Dat is alles. De naam van de provider JPA, de eigenschappen ervan en de kenmerken JDBC van de gegevensbron staan nu in het configuratiebestand van Spring.
4.1.6. Het Spring-configuratiebestand
We hebben gezegd dat de klasse [DaoJpa] een door Spring beheerde bean is. Dit gebeurt via een configuratiebestand. Dit bestand bevat ook de configuratie voor de toegang tot de database en het transactiebeheer. Het moet zich in de ClassPath van het project bevinden. We plaatsen het in de tak [Other sources]:
![]() |
Het bestand [spring-config-dao.xml] ziet er als volgt uit:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<!-- toepassingslagen -->
<bean id="dao" class=" " />
<!-- EntityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<!--
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
-->
</bean>
</property>
</bean>
<!-- de gegevensbron DBCP -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/dbrdvmedecins2" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<!-- de transactiebeheerder -->
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- vertaling van uitzonderingen -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<!-- persistentie -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>
Dit is een bestand dat compatibel is met Spring 2.x. We hebben niet geprobeerd om de nieuwe functies van de 3.x-versies te gebruiken.
- regels 2-4: de root-tag <beans> van het configuratiebestand. We geven geen toelichting op de verschillende attributen van deze tag. Zorg ervoor dat je de tekst kopieert en plakt, want een fout in een van deze attributen leidt tot fouten die soms moeilijk te begrijpen zijn,
- regel 7: de bean "dao" is een verwijzing naar een instantie van de klasse [rdvmedecins.dao.DaoJpa]. Er wordt één enkele instantie aangemaakt (singleton) die de laag [dao] van de applicatie implementeert,
- regels 24-29: er wordt een gegevensbron gedefinieerd. Deze levert de "verbindingspool"-service waar we het over hebben gehad. Hier wordt [DBCP] uit het Apache Commons-project DBCP [http://jakarta.apache.org/commons/dbcp/] gebruikt,
- regels 25-28: om verbindingen met de doeldatabase tot stand te brengen, moet de gegevensbron weten welke driver JDBC wordt gebruikt (regel 25), de URL van de database (regel 26), de gebruiker van de verbinding en zijn wachtwoord (regels 27-28),
- regels 10-21: configureren de JPA-laag,
- regel 10: definieert een bean van het type [EntityManagerFactory] die objecten van het type [EntityManager] kan aanmaken om de persistentie-contexten te beheren. De geïnstantieerde klasse [LocalContainerEntityManagerFactoryBean] wordt geleverd door Spring. Deze heeft een aantal parameters nodig om te worden geïnstantieerd, gedefinieerd in de regels 11-20,
- regel 11: de gegevensbron die moet worden gebruikt om verbindingen met SGBD tot stand te brengen. Dit is de bron [DBCP] die is gedefinieerd in de regels 24-29,
- regels 12-20: de te gebruiken implementatie JPA,
- regel 13: definieert Hibernate als de te gebruiken implementatie JPA,
- regel 14: het dialect SQL dat Hibernate moet gebruiken met het doel SGBD, in dit geval MySQL5,
- regel 16 (uitgecommentarieerd): vraagt dat de door Hibernate uitgevoerde SQL-opdrachten op de console worden gelogd,
- regel 17 (uitgecommentarieerd): zorgt ervoor dat bij het opstarten van de applicatie de database wordt aangemaakt (drop en create),
- regel 32: geeft aan dat transacties worden beheerd met Java-annotaties (deze hadden ook in spring-config.xml kunnen worden gedeclareerd). Het gaat met name om de annotatie @Transactional in de klasse [DaoJpa],
- regels 33-35: hierin wordt de te gebruiken transactiebeheerder gedefinieerd,
- regel 33: de transactiemanager is een klasse die door Spring wordt geleverd,
- regel 34: de transactiebeheerder van Spring moet de klasse EntityManagerFactory kennen die de laag JPA beheert. Dit is de klasse die is gedefinieerd op de regels 10-21,
- regel 41: definieert de klasse die de Spring-persistentie-annotaties beheert,
- regel 38: definieert de Spring-klasse die onder meer de annotatie @Repository beheert, waardoor een klasse met deze annotatie in aanmerking komt voor de vertaling van de native uitzonderingen van de driver JDBC van SGBD naar generieke Spring-uitzonderingen van het type [DataAccessException]. Deze omzetting kapselt de native uitzondering JDBC in een type [DataAccessException] met verschillende subklassen:

Dankzij deze vertaling kan het clientprogramma uitzonderingen generiek afhandelen, ongeacht de doel-SGBD. We hebben de annotatie @Repository niet gebruikt in onze Java-code. Daarom is regel 38 overbodig. We hebben deze regel puur ter informatie laten staan.
We zijn klaar met het Spring-configuratiebestand. Dit is ontleend aan de Spring-documentatie. Het aanpassen aan verschillende situaties komt vaak neer op twee wijzigingen:
- die van de doeldatabase: regels 24-29,
- de aanpassing van de implementatie JPA: regels 12-20.
Bij het uitvoeren van de code worden alle beans uit het configuratiebestand geïnstantieerd. We zullen zien hoe dat gebeurt.
4.1.7. De testklasse JUnit
![]() |
We hadden de laag [DAO] van het project EJB getest met een test JUnit. We doen hetzelfde voor de laag [DAO] van het Spring-project:
- in [1] en [2], waarbij we de test JUnit tussen de twee projecten hebben gekopieerd en geplakt,
- in [3] vertoont de geïmporteerde test fouten in de nieuwe omgeving.
![]() |
De gemelde fout [1] betreft de externe interface van EJB, die niet meer bestaat. Bovendien was de initialisatiecode van het veld [dao] op regel 19 een aanroep van JNDI die specifiek was voor EJB (regels 25-28). Om het veld [dao] op regel 19 te instantiëren, moeten we het Spring-configuratiebestand gebruiken. Dit gebeurt als volgt:
![]() |
- regel 21: het type van de interface is nu [IDao],
- regel 28: instantiëert alle beans die in het bestand [spring-config-dao.xml] zijn gedeclareerd, met name deze:
<bean id="dao" class="rdvmedecins.dao.DaoJpa" />
- regel 29 vraagt aan de Spring-context van regel 28 een verwijzing naar de bean met id="dao". We krijgen dan een verwijzing naar de singleton [DaoJpa] (hierboven class) die Spring heeft geïnstantieerd.
De regels 28-29 vormen de volgende blokken (roze stippellijnen):
![]() |
Wanneer de tests van de client JUnit worden uitgevoerd, is de laag [DAO] geïnstantieerd. We kunnen dus de methoden ervan testen. Merk op dat er geen server nodig is om deze test uit te voeren, in tegenstelling tot de test van EJB en [DAO], waarvoor de Glassfish-server nodig was. Hier wordt alles uitgevoerd binnen dezelfde JVM.
We kunnen nu de test JUnit uitvoeren. De server MySQL moet gestart zijn. De resultaten zijn als volgt:
![]() |
De test JUnit is geslaagd. Laten we de testlogs bekijken, net zoals we dat bij de test van EJB hebben gedaan:
- regels 1-4: Spring-logs,
- regels 5-10: logberichten van Hibernate,
- regel 11: Spring rapporteert alle beans die het heeft geïnstantieerd. Als eerste zien we de bean [dao],
- regels 12 en verder: de logboeken van de test JUnit,
- regels 60-65: we zien duidelijk de uitzondering die wordt veroorzaakt door het toevoegen van een afspraak die al in de database staat. Ter herinnering: bij de EJB hadden we deze uitzondering niet gehad vanwege een serialisatieprobleem.
De laag [dao] is operationeel. We bouwen nu de laag [métier].
4.2. De laag [métier]
![]() |
We gaan op dezelfde manier te werk als bij de laag [DAO], door het project EJB te kopiëren en in het Spring-project te plakken.
4.2.1. Het NetBeans-project
We maken een nieuw Maven-project van het type [Java Application], waarbij we alles verwijderen wat we niet willen behouden uit [1]:
![]() |
4.2.2. De afhankelijkheden van het project
In de architectuur:
![]() |
De laag [métier] is gebaseerd op de laag [dao]. We voegen daarom een afhankelijkheid toe aan het vorige project:
![]() |
- in [1] en [2] voegen we een afhankelijkheid toe aan het project van de laag [dao],
- in [3] heeft deze afhankelijkheid geleid tot andere afhankelijkheden, namelijk die van het project van de laag [dao].
![]() |
- in [1] en [2] worden de Java-broncodes van het project EJB gekopieerd naar het Spring-project,
- naar [3]; de geïmporteerde broncodes vertonen fouten in hun nieuwe omgeving.
We beginnen met het verwijderen van de externe en lokale interfaces uit de laag [métier] die niet meer bestaan in [4]:
![]() |
- in [5] hebben de fouten in de klasse [Metier] verschillende oorzaken:
- het gebruik van het pakket [javax.ejb], dat niet meer bestaat;
- het gebruik van de interface [IDaoLocal], die niet meer bestaat;
- het gebruik van de interfaces [IMetierRemote] en [IMetierLocal], die niet meer bestaan.
We
- verwijderen alle foutieve regels die betrekking hebben op het pakket [javax.ejb],
- vervangen de interface [IDaoLocal] door de interface [IDao],
- vervangen de interfaces [IMetierRemote] en [IMetierLocal] door de interface [IMetier].
![]() |
- in [6], de aldus gecorrigeerde klasse,
- In [7] zijn er geen fouten meer.
We hebben de verwijzingen naar EJB verwijderd, maar nu moeten we hun eigenschappen terugvinden:
![]() |
- regel 22: we hadden een singleton. Dit gedrag wordt bereikt door van de klasse een door Spring beheerde bean te maken,
- regel 23: elke methode vond plaats binnen een transactie. Dit wordt bereikt met de Spring-annotatie @Transactional,
- regels 27-28: de verwijzing naar de laag [DAO] werd verkregen via injectie door de container EJB. We zullen gebruikmaken van Spring-injectie.
De code van de klasse [Metier] van het Spring-project ziet er dus als volgt uit:
![]() |
Dat was het wat betreft de Java-code. De rest gebeurt in het Spring-configuratiebestand.
4.2.3. Het Spring-configuratiebestand
We kopiëren het Spring-configuratiebestand van het [DAO]-laagproject naar het [métier]-laagproject. We beginnen met het aanmaken van de branch [Other Resources] in het project van de laag [métier], als deze nog niet bestaat:
![]() |
- in [1], op het tabblad [Files], maken we een submap aan in de map [main],
- in [2] moet deze [resources] heten,
- in [3], in het tabblad [Projects], is de tak [Other Sources] aangemaakt.
We kunnen nu overgaan tot het kopiëren en plakken van het Spring-configuratiebestand:
![]() |
- in [1] kopiëren we het bestand uit het project [DAO] naar het project [métier] [2],
- in [3], het gekopieerde bestand.
Het gekopieerde configuratiebestand configureert de laag [DAO]. We voegen er een bean aan toe om de laag [métier] te configureren:
- regel 2: de bean van de laag [DAO],
- regels 3-5: de bean van de laag [métier],
- regel 3: de bean heet métier (attribuut id) en is een instantie van de klasse [rdvmedecins.metier.service.Metier] (attribuut class). Deze bean wordt net als de andere beans geïnstantieerd bij het opstarten van de applicatie.
Laten we de code van de bean [rdvmedecins.metier.service.Metier] nog eens bekijken:
package rdvmedecins.metier.service;
...
public class Metier implements IMetier, Serializable {
// DAO-laag
private IDao dao;
public Metier() {
}
- regel 8: het veld [dao] wordt door Spring geïnstantieerd tegelijk met de bean métier. Laten we teruggaan naar de definitie van deze bean in het Spring-configuratiebestand:
- regel 4: de tag <property> wordt gebruikt om velden van de geïnstantieerde bean te initialiseren. De naam van het veld wordt aangegeven door het attribuut name. Het is dus het veld `dao` van de klasse `[rdvmedecins.metier.service.Metier]` dat zal worden geïnstantieerd. Dit gebeurt via een methode `setDao` die moet bestaan. De waarde die eraan wordt toegewezen, is die van het attribuut `ref`. Deze waarde is hier de referentie van de `dao`-bean uit regel 2.
Eenvoudiger gezegd, in de code:
package rdvmedecins.metier.service;
...
public class Metier implements IMetier, Serializable {
// DAO-laag
private IDao dao;
public Metier() {
}
Het veld dao op regel 19 wordt door Spring geïnitialiseerd met een verwijzing naar de laag [dao]. Dat is precies wat we wilden. Het veld **dao** wordt door Spring geïnitialiseerd via een *setter* die we moeten toevoegen:
// setter
public void setDao(IDao dao) {
this.dao = dao;
}
We hernoemen het Spring-configuratiebestand om rekening te houden met de wijzigingen:
![]() |
We zijn nu klaar voor een test. We gebruiken opnieuw de consoletest die we hebben gebruikt om de EJB en [Metier] te testen.
4.2.4. Test van de [métier]-laag
De test zal plaatsvinden met de volgende architectuur:
![]() |
We kopiëren de consoletest van het project EJB naar het Spring-project:
![]() |
- in [1] en [2], het kopiëren en plakken tussen de twee projecten,
- in [3] vertoont de geïmporteerde code fouten.
![]() |
De geïmporteerde code bevat twee soorten fouten:
- regel 13: de interface [IMetierRemote] is vervangen door de interface [IMetier],
- regels 24-27: de instantiëring van de laag [métier] gebeurt niet langer via een aanroep van JNDI, maar door instantiëring van de beans uit het Spring-configuratiebestand.
We corrigeren deze twee punten:
![]() |
- regel 22: het bestand [spring-config-metier-dao.xml] wordt gebruikt. Alle beans in dit bestand worden dan geïnstantieerd. Daaronder bevinden zich de volgende:
<!-- toepassingslagen -->
<bean id="dao" class="rdvmedecins.dao.DaoJpa" />
<bean id="metier" class="rdvmedecins.metier.service.Metier">
<property name="dao" ref="dao"/>
</bean>
Deze twee beans vertegenwoordigen de lagen [DAO] en [métier] van de testarchitectuur:
![]() |
Zodra dit is gebeurd, kan de test worden uitgevoerd:
![]() |
De testlogs zien er dan als volgt uit:
- regels 1-4: de logbestanden van Spring en Hibernate,
- regel 5: de door Spring geïnstantieerde beans. Let vooral op de DAO- en business-beans,
- regels 6-53: de testlogs. Deze komen overeen met de resultaten die werden verkregen bij de test van het project EJB. We verwijzen de lezer naar de opmerkingen bij die test (paragraaf 3.5.3).
We hebben de laag [métier] opgebouwd. We gaan nu verder met de laatste laag, de laag [web].
4.3. De laag [web]
![]() |
Om de laag [web] te bouwen, gaan we op dezelfde manier te werk als bij de twee andere lagen, namelijk door te kopiëren en te plakken vanuit de laag [web] van het project EJB.
4.3.1. Het NetBeans-project
We maken eerst een webproject aan:
![]() |
- In [1] maken we een nieuw project aan,
- in [2] een Maven-project van het type [Web Application],
- in [3] geven we het een naam,
![]() |
- in [4], kiezen we deze keer voor de Tomcat-server en niet voor Glassfish, die werd gebruikt voor het project EJB,
- in [5] is het verkregen project,
- in [6], het project na het verwijderen van [index.jsp] en het pakket van [Source Packages].
4.3.2. De afhankelijkheden van het project
Laten we eens kijken naar de architectuur van het project:
![]() |
De laag [web] heeft de lagen [métier], [DAO] en [JPA] nodig. Deze maken deel uit van de twee projecten die we zojuist hebben gebouwd. Vandaar een afhankelijkheid van elk van deze projecten:
![]() |
- in [1] voegen we de afhankelijkheid van het Spring-/bedrijfsproject toe,
- in [2] is het Spring-/businessproject toegevoegd. Aangezien dit project zelf een afhankelijkheid had van het Spring-project / DAO / JPA, is dit automatisch toegevoegd aan de afhankelijkheden van [3].
Laten we terugkeren naar de structuur van onze applicatie:
![]() |
De weblaag is een JSF-laag. We hebben dus de Java Server Faces-bibliotheken nodig. De Tomcat-server beschikt hier niet over. De afhankelijkheid zal dus niet de scope [provided] hebben, zoals bij de Glassfish-server het geval was, maar de scope [compile], wat de standaard scope is wanneer er geen scope wordt opgegeven.
We voegen deze afhankelijkheden rechtstreeks toe aan de code van [pom.xml]:
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mv-rdvmedecins-spring-metier</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
- De regels 7-16 zijn toegevoegd aan het bestand [pom.xml]. Dit zijn de afhankelijkheden ten opzichte van JSF. Dit zijn de afhankelijkheden die worden gebruikt in het project EJB / Glassfish. Merk op dat ze geen <scope>-tag hebben. Ze hebben dus standaard het bereik [compile]. De bibliotheek JSF wordt daarom opgenomen in het archief [war] van het webproject.
Nadat we deze afhankelijkheden aan het bestand [pom.xml] hebben toegevoegd, compileren we het project zodat ze worden gedownload.
4.3.3. Overzetten van het project JSF / Glassfish naar het project JSF / Tomcat
We kopiëren de volledige broncode van het project JSF / Glassfish naar het project JSF / Tomcat:
![]() |
- [1, 2, 3]: kopiëren van de webpagina’s van het oude project naar het nieuwe,
![]() |
- [1, 2, 3]: kopiëren van de Java-code van het oude project naar het nieuwe. Er zijn fouten. Dat is normaal. We zullen ze corrigeren,
![]() |
- in [1], in het tabblad [Files] van NetBeans, maken we een submap [resources] aan in de map [main],
- waardoor in het tabblad [Projects] de tak [Other Sources] [3] wordt aangemaakt,
![]() |
- [1, 2, 3]: de berichtbestanden worden van het oude project naar het nieuwe project gekopieerd.
4.3.4. Wijzigingen in het geïmporteerde project
We hebben gemeld dat de geïmporteerde Java-code fouten bevatte. Laten we deze eens bekijken:
![]() |
- in [1] is alleen de bean [Application] foutief,
- in [2] is de fout uitsluitend te wijten aan de interface [IMetierLocal], die niet meer bestaat. Hier is het opmerkelijk dat regel 20 niet als fout wordt gemarkeerd. De annotatie @EJB verwijst expliciet naar EJB en wordt hier herkend. Dit komt door de aanwezigheid van de afhankelijkheid [javaee-web-api-6.0] [3]. Java EE 6 heeft een architectuur geïntroduceerd waarmee een webapplicatie die gebruikmaakt van EJB zonder externe interface kan worden geïmplementeerd op servers die geen EJB-container hebben. Het volstaat dat de server de afhankelijkheid [javaee-web-api-6.0] levert. We zien namelijk dat deze het bereik [provided] [3] heeft.
In dit geval gaan we de afhankelijkheid [javaee-web-api-6.0] niet gebruiken. We verwijderen deze: [1]:
![]() |
![]() |
Dit leidt tot nieuwe fouten: [2]. We beginnen met die van de bean [Form]:
![]() |
- In [1] hebben de foutieve regels te maken met het ontbreken van het pakket [javax]. We verwijderen ze allemaal: [2]. De foutieve regels maakten van de klasse [Form] een bean met sessiebereik (regels 18-20 van [1]). Bovendien werd de bean [Application] op regel 25 geïnjecteerd. Deze informatie wordt overgezet naar het configuratiebestand van JSF en [faces-config.xml].
Laten we verdergaan met de bean [Application]:
![]() |
We verwijderen alle foutieve regels uit [1] en wijzigen de interface [IMetierLocal] in de regels 13 en 21 in [IMetier]. In [2] zijn er geen fouten meer. In [1] hebben we de regels 15-16 verwijderd die van de klasse [Application] een bean met bereik application. maakten. Deze informatie wordt verplaatst naar het configuratiebestand van JSF [faces-config.xml]. We hebben ook regel 20 verwijderd, die een verwijzing naar de laag [métier] in de bean injecteerde. Deze wordt nu door Spring geïnitialiseerd. We beschikken al over het benodigde configuratiebestand; dit is dat van het Spring / Métier-project. We kopiëren het:
![]() |
- naar [1, 2]. We kopiëren het Spring-configuratiebestand van het project Spring / Métier naar het project Spring / JSF,
![]() |
In [3], het resultaat.
In de bean [Application] moet dit configuratiebestand worden gebruikt om een verwijzing naar de laag [métier] te verkrijgen. Dit gebeurt in de methode [init]:
package beans;
...
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Application {
// bedrijfslaag
private IMetier metier;
...
public Application() {
}
@PostConstruct
public void init() {
try {
// instantie van de laag [métier]
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config-metier-dao.xml");
metier = (IMetier) ctx.getBean("metier");
// artsen en klanten worden in de cache opgeslagen
...
} catch (Throwable th) {
...
}
...
}
- regel 20: de beans uit het Spring-configuratiebestand worden geïnstantieerd,
- regel 21: er wordt een verwijzing aangevraagd naar de business-bean, dus naar de laag [métier].
Over het algemeen moet het instantiëren van Spring-beans plaatsvinden in de init-methode van de bean met applicatiebereik. Er is een andere methode waarbij het instantiëren van de beans wordt uitgevoerd door een Spring-servlet. Dit houdt in dat het bestand [web.xml] moet worden aangepast en dat er een afhankelijkheid moet worden toegevoegd aan het artefact [spring-web]. We hebben dit hier niet gedaan om in lijn te blijven met wat in de eerdere codeversies werd gebruikt.
We hebben de annotaties verwijderd uit de klassen [Application] en [Form] die deze tot JSF-beans maakten. Deze klassen moeten JSF-beans blijven. In plaats van annotaties gebruiken we nu het configuratiebestand van JSF [WEB-INF / faces.config.xml] om de beans te declareren.
![]() |
Dit bestand ziet er nu als volgt uit:
<?xml version='1.0' encoding='UTF-8'?>
<!-- =========== FULL CONFIGURATION FILE ================================== -->
<faces-config version="2.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
<application>
<!-- het berichtenbestand -->
<resource-bundle>
<base-name>
messages
</base-name>
<var>msg</var>
</resource-bundle>
<message-bundle>messages</message-bundle>
</application>
<!-- de bean applicationBean -->
<managed-bean>
<managed-bean-name>applicationBean</managed-bean-name>
<managed-bean-class>beans.Application</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
<!-- de form-bean -->
<managed-bean>
<managed-bean-name>form</managed-bean-name>
<managed-bean-class>beans.Form</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>application</property-name>
<value>#{applicationBean}</value>
</managed-property>
</managed-bean>
</faces-config>
- de regels 10-19 configureren het berichtenbestand. Dit was de enige configuratie die we hadden in het project JSF / EJB,
- de regels 21-35 definiëren de beans van de applicatie JSF. Dit was de standaardmethode bij JSF 1.x. JSF 2 heeft annotaties geïntroduceerd, maar de methode van JSF en 1.x wordt nog steeds ondersteund,
- regels 21-25: declareren de bean applicationBean,
- regel 22: de naam van de bean. Je zou in de verleiding kunnen komen om de naam ‘application’ te gebruiken. Dit moet je vermijden, want dat is de naam van een vooraf gedefinieerde bean van JSF,
- regel 23: de volledige naam van de bean-klasse,
- regel 24: het bereik ervan,
- regels 27-35: definiëren de form-bean,
- regel 28: de naam van de bean,
- regel 29: de volledige naam van de bean-klasse,
- regel 30: het bereik ervan,
- regels 31-34: definiëren een eigenschap van de klasse [beans.Form],
- regel 32: de naam van de eigenschap. De klasse [beans.Form] moet een veld met deze naam hebben en de bijbehorende setter,
- regel 33: de waarde van het veld. Hier is dat de verwijzing naar de bean applicationBean die op regel 21 is gedefinieerd. Hier vindt dus de injectie plaats van de bean met bereik application in de bean met bereik session, zodat deze toegang heeft tot de gegevens met bereik application.
We hebben hierboven vermeld dat het veld [application] van de bean [beans.Form] zou worden geïnitialiseerd via een setter. Dit veld moet dus worden toegevoegd aan de klasse [beans.Form] als het nog niet bestaat:
public void setApplication(Application application) {
this.application = application;
}
4.3.5. Testen van de applicatie
Onze applicatie is nu foutloos en klaar om te worden getest:
![]() |
- in [1], het gecorrigeerde project,
- in [2] bouwen we het,
- in [3] voeren we het uit. SGBD en MySQL moeten gestart zijn. De Tomcat-server wordt dan gestart ([4]) als dat nog niet het geval was, waarna de startpagina van de applicatie wordt weergegeven ([5]):
![]() |
Vanaf hier zien we de besproken applicatie. We laten het aan de lezer over om te controleren of deze werkt. Laten we de applicatie nu stoppen:
![]() |
- in [1] wordt de app ontladen,
- in [2] is deze niet meer aanwezig.
Laten we nu eens kijken naar de -logs van Tomcat:
De regels 2 en 4 duiden op een storing bij het afsluiten van de applicatie. Regel 4 geeft aan dat er waarschijnlijk sprake is van een geheugenlek. Dit gebeurt inderdaad en na een tijdje is NetBeans niet meer bruikbaar. Dit probleem is bijzonder irritant, omdat je NetBeans dan bij elke nieuwe uitvoering van het project opnieuw moet opstarten. Dit probleem kwam al aan bod in het document "Inleiding tot Struts 2 aan de hand van voorbeelden" [http://tahe.developpez.com/java/struts2].
Op internet is veel informatie te vinden over deze fout. Deze treedt op wanneer een applicatie herhaaldelijk in en uit Tomcat wordt geladen. Na verloop van tijd krijg je de foutmelding java.lang.OutOfMemoryError: PermGen space. Het lijkt erop dat er geen oplossing is om deze fout te voorkomen wanneer deze voortkomt uit archieven van derden (jar), zoals hier het geval is. Je moet Tomcat dan opnieuw opstarten om de fout te verhelpen.
Het optreden van deze fout kan echter worden uitgesteld. Ten eerste vergroten we de ruimte van het geheugen dat overliep.
![]() |
- in [1] gaan we naar de eigenschappen van de Tomcat-server,
- in [2], op het tabblad [Platform], stellen we de waarde in voor het geheugen dat overloopt. Hier hebben we 1 GB ingesteld omdat we een totaal geheugen van 8 GB hadden. Bij een kleiner geheugen kun je 512M (512 megabyte) instellen.
Vervolgens plaatsen we het stuurprogramma JDBC van MySQL in <tomcat>/lib, waarbij <tomcat> de installatiemap van Tomcat is.
![]() |
- in [1], noteer je in de eigenschappen van Tomcat de installatiemap <tomcat>,
- in <tomcat>/lib [2] plaatsen we een recente driver JDBC ter vervanging van MySQL en [3].
Vervolgens verwijderen we de afhankelijkheid die het project had van de driver JDBC van MySQL en [4].
![]() |
Zodra dit is gebeurd, testen we de applicatie. We constateren dat we de applicatie herhaaldelijk kunnen laden en ontladen. De problemen met geheugenlekken zijn echter niet opgelost. Ze treden gewoon later op.
4.4. Conclusion
We hebben de applicatie JSF / EJB / Glassfish overgezet naar een JSF / Spring / Tomcat-omgeving. Dit gebeurde voornamelijk door middel van kopiëren en plakken tussen de twee projecten. Dit was mogelijk omdat de technologieën Spring en EJB3 sterke overeenkomsten vertonen. EJB3 is namelijk ontwikkeld nadat Spring beter presteerde dan de EJB2. EJB3 heeft vervolgens de goede ideeën van Spring overgenomen.
4.5. Tests met Eclipse
![]() |
- in [1] importeren we de drie Spring-projecten,
- in [2] selecteren we de test JUnit uit de laag [DAO] en voeren we deze uit in [3],
![]() |
![]() |
- in [4] is de test geslaagd,
- in [5], de logbestanden van de console.
![]() |
- in [6A] [6B], wordt de consolecontroller van de laag [métier] uitgevoerd,
- in [7], de verkregen consoleweergave,
![]() |
- in [8] [9], wordt het webproject uitgevoerd op een Tomcat 7-server [10],
![]() |
- en [11], wordt de startpagina van de applicatie weergegeven in de interne browser van Eclipse.





































































