Architecture JEE classique
Introduction
Dans l'approche JEE traditionnelle, la pile de spécifications prévues est la suivante :
- CDI (Context and Dependency Injection) : Injection de dépendances.
- JPA : Accès aux données.
- EJB (Enterprise Java Bean) : Construction des services métiers.
- JSF (Java Server faces) : Construction des applications WEB par une approche composants et événements.
- JAX-RS : Construction d'API REST.
CDI: Context and Dependency Injection
Définition d'un POJO avec un nom et une portée :
package myapp.cdisample; import java.io.Serializable; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Named; @RequestScoped @Named("normal") public class Home implements Serializable { private static final long serialVersionUID = 1L; String place; // getter / setter }
Injection via les annotations :
package myapp.cdisample; import java.io.Serializable; import jakarta.inject.Inject; import jakarta.inject.Named; @Named("person") public class Person implements Serializable { private static final long serialVersionUID = 1L; @Inject @Named("normal") private Home home; // getter / setter }
Autres possibilités :
- Qualification des instances,
- producteurs et recycleurs d'instances,
- abonnement à des événements,
EJB: Enterprise java Bean Stateless
Déroulement (exploitation des architectures multi-processeurs-coeurs) :
thread 1 : <--- C1 sur A1 ---><--- C2 sur A1 ---> thread 2 : <------- C3 sur A2 -------> thread 3 : <---- C4 sur B1 ---->
Avec une troisième instances de A :
thread 1 : <--- C1 sur A1 ---> thread 4 : <--- C2 sur A3 ---> thread 2 : <------- C3 sur A2 -------> thread 3 : <---- C4 sur B1 ---->
La montée en charge implique une augmentation du nombre d'instances.
Gestion automatique (mais paramétrée) par le serveur d'applications.
EJB Statefull
EJB avec état utilisé par un seul client (non simultanément).
Utilité : représentation d'un utilisateur et fonctions associées.
EJB Singleton
EJB a instance unique (avec état) utilisé par plusieurs clients.
Déroulement (parallélisme des read et mise en série des write) :
<---- read 1 ----> <----- read 5 -----> <----- read 2 ------> <-- write 3 --> <-- read 4 -->
EJB: Mise en oeuvre de JPA
@PersistenceContext(unitName = "myBase") EntityManager em; public List<User> findAllUsers() { TypedQuery<Person> q = em.createNamedQuery("findAllUsers", User.class); return q.getResultList(); }
Le serveur d'applications gère (via les proxys) :
- l'ouverture de la transaction
- la validation de la transaction
- les erreurs d'exécution
Approche transactionnelle (très utile pour les opérations complexes).
EJB: Autres fonctions
- définition de traitements périodiques (similaire à cron d'UNIX)
- mise en place d'intercepteur (programmation par aspects)
- définition de traitements asynchrones (pour les traitements longs)
- EJB orientés message : traitement d'un file de messages (requêtes)
JSF: Java Server Faces
Principes : Framework WEB basé sur l'architecture MVC:
- View : facelet (document XML doté d'un langage d'expression)
- Controler : Managed beans instanciés par le framework
- Model : POJO et Managed beans
Caractéristiques :
- Utilisation d'une approche composant
- Mise en correspondance automatique entre POJO et Facelet
- Framework Javascript de gestion des pages (AJAX)
- Processus de validation
- Présence de nombreuses librairies externes (PrimeFaces, ...)
JSF: Un premier exemple
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" > <h:body> <h1><h:outputText value="#{helloControler.hello}" /></h1> </h:body> </html>
package myapp; import jakarta.faces.bean.ManagedBean; import jakarta.faces.bean.SessionScoped; @ManagedBean(name = "helloControler") @SessionScoped public class MyControler { private String hello = "Hello, world"; public String getHello() { return hello; } public void setHello(String hello) { this.hello = hello; } }
JSF: Utilisation d'un formulaire
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" > <h:body> <h1><h:outputText value="#{helloControler.hello}" /></h1> <h:form> <h:inputText id="text" value="#{helloControler.hello}" required="true" requiredMessage="Le texte est obligatoire"> <f:validateLength minimum="3" maximum="15" /> </h:inputText> <h:message errorClass="error" for="text" /> <br/> <h:commandButton value="Submit" action="#{helloControler.sayHello}" /> </h:form> </h:body> </html>
Amélioration du contrôleur :
package myapp; import jakarta.faces.bean.ManagedBean; import jakarta.faces.bean.SessionScoped; @ManagedBean(name = "helloControler") @SessionScoped public class MyControler { private String hello = " Hello, world"; // getter / setter public String getHello() { return hello; } public void setHello(String hello) { this.hello = hello; } public String sayHello() { hello = hello.toUpperCase(); return null; } }
JSF: Autres caractéristiques
- Grande facilité de mise en place d'AJAX
- Possibilités de navigation avancées
- Cinq portés disponibles:
- application
- session
- conversation (notion de sous-session)
- vue (on reste sur la même page JSF)
- requête
- Traitement des événement HTML (éventuellement en AJAX)
- Possibilité de couplage avec bootstrap ou Angular
Intégration
Dans une application, l'API CDI va
- Injecter les EntityManager dans les EJB.
- Injecter les EJB dans d'autres EJB et dans les contrôleurs JSF
- Injecter les beans de portée vue, requêtes, session dans les contrôleurs JSF