1- CDI-Cours

publicité
Context and Dependency Injection
Maxime Lefrançois ([email protected]),
M2 MIAGE Casablanca 2012-2013
Introduction
2
Questions rébarbatives
Pour un objet A ...








3
Combien de clients est-ce que A peut avoir ?
est-ce que A est multi-threadé ?
Comment j’ai accès à A dans un autre objet B ?
Est-ce que je dois le détruire explicitement ?
Où dois-je garder une référence à A si je ne l’utilise pas ?
Comment définir des implémentations alternatives, pour en
changer au moment du déploiement ?
Comment partager cet objet entre d’autres objets ?
Context and Dependency Injection
= CDI (JSR-299)
CDI est un modèle riche de programmation

couplage faible avec typage fort
4
CDI
Gestion du cycle de vie des objets avec état, liés à des
contextes
injection de dépendance avec types
intercepteurs d’objets et décorateurs
notifications d’évènements
+ SPI (pour extensions)





5
CDI

aboutissement des frameworks java:
Seam, Guice, Spring

Au coeur de la plateforme Java EE
mais pas limité à Java EE

implémentation de référence de CDI : Weld
(Seam Framework)

6
Beans – couplage faible
Un objet avec état lié à un contexte = un bean
 couplage faible avec typage fort
1. un bean spécifie seulement le type et la sémantique des
beans dont il dépend,
il ne connait pas:




7
leur cycle de vie,
leur implémentation concrete
leur modèle de threading
Beans – couplage faible
Un objet avec état lié à un contexte = un bean
 couplage faible avec typage fort
2. un bean spécifie seulement le type et la sémantique des
beans dont il dépend,
leur implémentation, leur cycle de vie, ...
peuvent varier en fonction du scénario de déploiement

8
Beans – couplage faible
Un objet avec état lié à un contexte = un bean
 couplage faible avec typage fort
3. Les notifications d’évènement découplent complètement:
les producteur d’évènement
les consommateurs d’évènements

9
Beans – couplage faible
Un objet avec état lié à un contexte = un bean
 couplage faible avec typage fort
4. Les intercepteurs découplent:
les considérations technique
la logique métier

(programmation par aspect)
exemple: sécurité, transactions, ...
10
Beans – couplage faible
Un objet avec état lié à un contexte = un bean
 couplage faible avec typage fort
5. Les décorateurs permettent de compartimenter les
logiques métier

11
Beans – typage fort
Un objet avec état lié à un contexte = un bean
 couplage faible avec typage fort
6. le couplage ne se fait pas par des chaînes de caractères,
on utilise des annotations:
les qualifieurs

12
Beans – typage fort
Un objet avec état lié à un contexte = un bean
 couplage faible avec typage fort
7. l’utilisation du fichier descripteur META-INF/beans.xml
est limitée pour les informations qui dépendent du
déploiement

13
Notion de Bean


Quels beans on connaît ?
C’est quoi un bean ?
14
Notion de Bean

Quels beans on connaît ?

les JSF Managed Bean:

Un objet géré par un conteneur, avec des restrictions minimes de
programmation
~ un POJO (Plain Old Java Object)

Ont des propriétés

Supportent quelques services basiques:



15
c’est quoi les propriétés d’un Managed Bean ?
injection de ressources
callbacks de cycle de vie (@PostConstruct, @PreDestroy, ...)
des intercepteurs (définis dans le bean = couplage fort !!!)
Exercice 1


Pour commencer, une petite application pour vérifier
quelques notions des Servlets et JSF2…
Corrigez les erreurs !
16
Notion de Bean

Quels beans on connaît ?






17
les javabeans
les Managed Bean
les EJB Session Beans / Message-driven Beans
Les beans selon Spring
Les beans selon Seam
...
Notion de Bean
C’est quoi un bean ?
CDI donne une définition claire:


Tout objet qui a un constructeur sans paramètre
(ou un constructeur annoté @Inject)
(ou un producteur de beans)
18
Un exemple d’injection
Une classe avec une méthode qui découpe un texte en phrases
public class SentenceParser {
public List<String> parse(String text) { ... }
}
est-ce que c’est un bean ?
Un stateless session bean capable de traduire des phrases
@Stateless
public class SentenceTranslator implements Translator {
public String translate(String sentence) { ... }
}
est-ce que c’est un bean ?
Son interface locale Translator
@Local
public interface Translator {
public String translate(String sentence);
}
19
est-ce que c’est un bean ?
Un exemple d’injection
On écrit donc une classe pour traduire un document en entier
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Inject
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
}
}
public String translate(String text) {
StringBuilder sb = new StringBuilder();
for (String sentence: sentenceParser.parse(text)) {
sb.append(sentenceTranslator.translate(sentence));
}
return sb.toString();
}
est-ce que c’est un bean ?
20
Un exemple d’injection
On écrit donc une classe pour traduire un document en entier
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Inject
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
}
}
Les paramètres
du constructeur annoté
@Inject seront injectés
public String translate(String text) {
StringBuilder sb = new StringBuilder();
for (String sentence: sentenceParser.parse(text)) {
sb.append(sentenceTranslator.translate(sentence));
}
return sb.toString();
}
est-ce que c’est un bean ? OUI.
Le conteneur va appeler le constructeur annoté @Inject,
et injecter d’autres beans dans les paramètres du constructeur.
21
Un exemple d’injection
On écrit donc une classe pour traduire un document en entier
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Inject
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
}
}
public String translate(String text) {
StringBuilder sb = new StringBuilder();
for (String sentence: sentenceParser.parse(text)) {
sb.append(sentenceTranslator.translate(sentence));
}
return sb.toString();
}
On peut maintenant injecter une instance de TextTranslator :
Dans un constructeur, une méthode, un attribut d’un bean
Ou dans un attribut ou une méthode d’une servlet ou d’un autre composant EJB
22
Un exemple d’injection
Exemple de Managed Bean qui utilise une instance injectée de TextTransla
@Named @RequestScoped
public class TranslateController {
@Inject TextTranslator textTranslator;
private String inputText;
private String translation;
// JSF action method, perhaps
public void translate() {
translation = textTranslator.translate(inputText);
}
public String getInputText() {
return inputText;
}
public void setInputText(String text) {
this.inputText = text;
}
}
public String getTranslation() {
return translation;
}
23
Utiliser CDI
24
Dans un projet JEE 6

Avec Netbeans Cocher la case « utiliser CDI » au moment de
la création du projet Java Web ou Java EE


Avec Glassfish:



Ça crée simplement un fichier descripteur META-INF/beans.xml
il suffit d’avoir un fichier descripteur META-INF/beans.xml (même
vide !)
Weld, l’implémentation de référencede CDI, est fournie
Avec Tomcat, Jetty, …

25
Suivre la procédure: http://docs.jboss.org/weld/reference/latest/enUS/html/environments.html#d0e5225
Projet Java SE avec CDI

On utilise l’implémentation de référence: Weld

http://www.seamframework.org/Weld/WeldDistributionDownloads

Le jar: weld-se-core.jar
Ou avec Maven:

<dependency>
<groupId>org.jboss.weld.se </groupId>
<artifactId>weld-se </artifactId>
<version>CHOISIR LA DERNIERE FINALE</version>
</dependency>

Est-ce qu’on doit écrire une classe principale avec un
main ?
26
Projet Java SE avec CDI

Est-ce qu’on doit écrire une classe principale avec un
main ? Réponse: NON !!!




Où est l’instance du conteneur de beans ???
C’est possible de l’instantier nous-même, mais compliqué.
Le plus simple: une méthode main est fournie avec weld-se,
Le point d’entrée de notre application est un écouteur


27
Écouteur de l’évènement ContainerInitialized
On récupère les paramètres de la ligne de commande par
injection @Singleton
public class HelloWorld
{
public void printHello(@Observes ContainerInitialized event,
@Parameters List<String> parameters) {
System.out.println("Hello " + parameters.get(0));
}
}
Exercice 2
²

Quelle différence entre les deux applications 2a, 2b ?

La classe Init:



La bonne façon d’avoir une méthode d’un bean appelée dès
que le l’application est déployée (servlets ok, injection ok …)
Le singleton est un singleton EJB !
A votre avis, pourquoi est-ce que le bean Generator est
instantié deux fois? (cf. la console)
28
Introduction à CDI
Anatomie d’un Bean







Un ensemble non vide de types
Un ensemble non vide de qualifieurs
Un contexte
En option: Un nom EL
Un ensemble de liens de type intercepteurs
Une implémentation
En option: être un bean alternatif
30
Type, qualifieur et injection de dépendance

On a une référence à un bean par injection de
dépendance, un attribut injecté spécifie un « contrat »
que le bean injecté doit respecter:


31
Un ensemble non vide de types
Un ensemble non vide de qualifieurs
Type, qualifieur et injection de dépendance

Ensemble non vide de types:

ex1:
public class Business {
...
}

ex2 :
public class BookShop
extends Business
implements Shop<Book> {
...
}
32
Type, qualifieur et injection de dépendance

Et si on souhaite injecter un objet de type Business ?
ambiguité !
Le client doit spécifier un/des qualifieurs

Un qualifieur est une annotation:
ex:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, PARAMETER, FIELD})
public @interface CreditCard {}

Permet de désambiguiser l’objet à injecter, sans utiliser
une chaîne de caractères
33
Type, qualifieur et injection de dépendance

Pour ce point d’injection:
@Inject @CreditCard PaymentProcessor paymentProcessor;

Le conteneur cherche un bean qui satisfait le contrat.



Si il en trouve exactement un, il injecte une instance de ce bean
Sinon, il lance une erreur
exemple de bean qui satisfait le contrat:
@CreditCard
public class CreditCardPaymentProcessor
implements PaymentProcessor { ... }
34
Type, qualifieur et injection de dépendance

Un ensemble non vide de types
toujours au moins le type Object

Un ensemble non vide de qualifieurs
Si aucun qualifieur n’est spécifié,
il y a le qualifieur par défaut: @Default
35
Exercice 3




1- Provoquez une erreur: point d’injection ambigüe,
2- Provoquez une erreur: point d’injection insatisfiable
3- Faites en sorte que le nombre affiché soit vraiment
aléatoire
A votre avis, pourquoi le nombre ne change pas ?
Et le bean generator n’est instantié qu’une seule fois ?
36
Contexte (scope)

Le contexte d’un bean définit le cycle de vie de ses
instances

Un contexte est représenté par une annotation
ex: @RequestScoped, @SessionScoped, …
37
Contexte (scope)

Une instance d’un bean session-scoped est liée à un
session d’un utilisateur et est partagé par toutes les
requêtes executées dans cette session
(on ne peut pas l’enlever, ni le changer)

Un bean a un contexte. Si aucun contexte n’est défini, le
contexte par défaut est: @Dependent
38
Nom EL (EL= Expression Language)

Pour référencer un bean et ses propriétés dans une JSF ou une JSP, on
associe un nom EL

Annotation @Named
ex:
public @SessionScoped @Named("cart")
class ShoppingCart implements Serializable {
...
public List<Item> getLineItems() {...}
....
}

On peut ensuite l’utiliser dans une JSF ou une JSP:
<h:dataTable value="#{cart.lineItems}" var="item">
...
</h:dataTable>
39
Nom EL (EL= Expression Language)

Pour référencer un bean et ses propriétés dans une JSF ou une JSP, on
associe un nom EL

Annotation @Named
ex:
public @SessionScoped @Named("cart")
class ShoppingCart implements Serializable {
...
public List<Item> getLineItems() {...}
....
}
Propriété lineItems !

On peut ensuite l’utiliser dans une JSF ou une JSP:
<h:dataTable value="#{cart.lineItems}" var="item">
...
</h:dataTable>
40
Nom EL (EL= Expression Language)

Valeur par défaut:

public @SessionScoped @Named
class ShoppingCart implements Serializable {
...
public List<Item> getLineItems() {...}
....
}

<h:dataTable value="#{???.lineItems}" var="item">
...
</h:dataTable>
41
Comme dans Exercice1
Alternatives

Un bean peut être déclaré être une implémentation
alternative:

public @Alternative
class MockPaymentProcessor extends PaymentProcessorImpl { ... }

Désactivées par défaut, on peut choisir une alternative à utiliser au moment
du déploiement en le spécifiant dans le descripteur META-INF/beans.xml
42
Intercepteurs


Existent dans Java EE 5
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
public class TracingInterceptor {
@AroundInvoke
public Object logCall(InvocationContext context) throws Exception{
System.out.println("Invoking method: " + context.getMethod());
return context.proceed();
System.out.println(« Finished invoking method: " + context.getMethod());
}
}

@Interceptors(TracingInterceptor.class, ...)
@Stateless
public class HelloWorldBean implements HelloWorld {
public void sayHello() {
System.out.println("Hello!");
}
}
43
Intercepteurs

Existent dans Java EE 5, mais contre-intuitif !


44
On spécifiait directement la classe de l’intercepteur dans l’EJB !
On spécifiait directement l’ordre des intercepteurs dans l’EJB !
Intercepteurs
Dans CDI:

1.
annotation de lien à un (groupe d’intercepteurs)
@InterceptorBinding
@Inherited
@Target( { TYPE, METHOD })
@Retention(RUNTIME)
public @interface Transactional {}
2. L’intercepteur déclare cette annotation:
public @Transactional @Interceptor
class TransactionInterceptor { ... }
3. On applique cet aspect à un bean:
public @SessionScoped @Transactional
class ShoppingCart implements Serializable { ... }
4. On active les intercepteurs et on définit leur ordre dans
le fichier descripteur MEAT-INF/beans.xml
45
Quelles classes sont des beans ?




Les Managed Beans
Les EJB Session Beans
Les Producer Methods
Les Producer Fields
46
(Injectables, décorables, interceptables, ...)
Les Managed Beans


Des POJOs gérés par le conteneur,
un petit ensemble de services:




injection de ressource,
callbacks du cycle de vie
intercepteurs
JSR-316 Managed Beans (22 pages)
47
Les Managed Beans


Annotation @ManagedBean
pas nécessaire avec CDI !
Le conteneur CDI considère chaque classe comme un
managed beans si elle:





n’est pas une classe non-static interne
est une classe concrètes, ou annotées @Decorator
n’est pas un composant EJB (un session bean...)
n’implémente pas javax.enterprise.inject.spi.Extension
a un constructeur approprié : soit


48
un constructeur sans paramètres
un constructeur annoté @Inject
Les Managed Beans

Attention, les JPA Entity Beans sont techniquement des
Managed Beans, mais
IL NE FAUT PAS INJECTER UN ENTITY BEAN
IL NE FAUT PAS ASSIGNER UN CONTEXTE AUTRE
QUE @Dependent A UN ENTITY BEAN
49
Les Session Beans

des services avancés proposés par le conteneur d’EJB:
sécurité et gestion des transactions au niveau des méthodes,
 gestion des accès concurrents,
 passivation des instances des stateful session beans
et pooling des stateless session beans,
 invocation de session beans distants ou de web services,
 timers, méthodes asynchrones,
 ...
JSR-318 Enterprise JavaBeans Specification (626 pages)


50
Session Bean ou Managed Bean ?

Dans CDI, On peut injecter:





Dans CDI,



un session bean dans un autre session bean,
Un managed dans un session bean,
Un session bean dans un managed bean,
...
Un managed bean peut observer un évènement lancé par un
session bean,
etc.
QUESTION: Quand doit-on utiliser un session bean
plutôt qu’un managed bean ?
51
Session Bean ou Managed Bean ?

Dans CDI, On peut injecter:





Dans CDI,



un session bean dans un autre session bean,
Un managed dans un session bean,
Un session bean dans un managed bean,
...
Un managed bean peut observer un évènement lancé par un
session bean,
etc.
QUESTION: Quand doit-on utiliser un session bean
plutôt qu’un managed bean ?
52
Quand on a besoin des services offerts
par le conteneur d’EJB !
Producer Methods

Comment injecter un int
au hasard entre 1 et 100 ?
53
Producer Methods

Comment injecter un int
au hasard entre 1 et 100 ?
@ApplicationScoped
public class RandomNumberGenerator {
private Random random = new Random(System.currentTimeMillis());
@Produces @Random @Named int getRandomNumber() {
return random.nextInt(100);
}
}
54
Producer Methods

Comment injecter un int
au hasard entre 1 et 100 ?
@ApplicationScoped
C’est
cette méthode qui sera appelée pour injecter
public
classd’un
RandomNumberGenerator
une
instance
bean avec le type int et{ le qualifieur
@Random
private Random random = new Random(System.currentTimeMillis());
@Produces @Random @Named int getRandomNumber() {
return random.nextInt(100);
}
}
Un constructeur
@Inject
public UnBean(@Random int rand, ...) { ... }
Un attribut
55
@Inject @Random int rand;
Des méthodes
...
Producer Methods

Comment choisir au moment de l’execution quelle
implémentation d’un type de bean on veut instantier et
injecter ?
56
Producer Methods

Comment choisir au moment de l’execution quelle
implémentation d’un type de bean on veut instantier et
injecter ?
Une Producer Method
57
Producer Methods

Comment injecter un objet qui est obtenu en requêtant
un service ou une ressource transactionnelle, par
exemple un requête JPA ?
58
Producer Methods

Comment injecter un objet qui est obtenu en requêtant
un service ou une ressource transactionnelle, par
exemple un requête JPA ?
Une Producer Method
59
Producer Fields

Un raccourci pour les cas simples,
plus simple que les Producer Methods:
Les Producer Fields
public class Shop {
@Produces PaymentProcessor paymentProcessor = ....;
@Produces @Catalog List<Product> products = ....;
}
60
Exercice4



Ecrivez une producer method et/ou un producer field
pour l’entier aléatoire (qualifieur @Rand) et l’entier max
Etudiez l’enchaînement des appels de méthode
Vérifiez que le bean Game est bien associé à une session
61
Injection
Points d’injection d’un bean

Maintenant on a des beans,
on peut les injecter.

Annotation @javax.inject.Inject
63
Points d’injection d’un bean

Constructeur d’un autre bean
public class Checkout {
private final ShoppingCart cart;
}
@Inject
public Checkout(ShoppingCart cart) {
this.cart = cart;
}
Un bean ne peut avoir qu’un seul
constructeur annoté @Inject
64
Points d’injection d’un bean

Méthode d’initialisation
public class Checkout {
private ShoppingCart cart;
@Inject
void setShoppingCart(ShoppingCart cart) {
this.cart = cart;
}
}
Un bean peut avoir plusieurs méthodes
d’initialisation
65
Points d’injection d’un bean

Injection d’attribut
public class Checkout {
private @Inject ShoppingCart cart;
}
Un bean peut avoir plusieurs méthodes
d’initialisation
66
Points d’injection d’un bean
1.
2.
3.
4.
67
Le conteneur appelle le constructeur du bean
(celui par défaut ou celui annoté @Inject),
pour obtenir une instance du bean.
Le conteneur initialise les valeurs des attributs injectés
du bean.
Le conteneur appelle les méthodes d’initialisation du
bean (sans ordre standard).
La méthode annotée @PostConstruct est appelée
Points d’injection d’un bean


D’autre injections de paramètres sont possibles dans CDI,
par exemple dans les Producer Methods
@Produces Checkout createCheckout(ShoppingCart cart) {
return new Checkout(cart);
}
68
Qu’est-ce qui est injecté ?
Algorithme typesafe resolution:
vérifie qu’un et un seul bean peut être injecté à chaque fois
Au moment de l’initialisation !

Le plus simple:
un seul bean d’un certain type,
et un point d’injection avec ce type...
69
Qu’est-ce qui est injecté ?

Si plusieurs beans correspondent pour le point d’injection
?




70
On peut utiliser un Qualifieur
Les Qualifieurs peuvent avoir des membres
On peut combiner plusieurs Qualifieurs
Certains beans peuvent être des Alternatives
Qualifieurs

Une annotation !
(et non pas une chaîne de caractères comme dans la
spécification des managed beans)


plus de sémantique
moins d’erreurs de typographie
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Synchronous {}
71
Qualifieurs

Qualifieur pour annoter:

Un bean
@Synchronous
public class SynchronousPaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
72
Qualifieurs

Qualifieur pour annoter:

Un point d’injection
@Inject @Synchronous PaymentProcessor syncPaymentProcessor;
@Inject
public void setPaymentProcessors(@Synchronous PaymentProcessor syncPaymentProcessor) {
this.syncPaymentProcessor = syncPaymentProcessor;
}
@Inject
public Checkout(@Synchronous PaymentProcessor syncPaymentProcessor) {
this.syncPaymentProcessor = syncPaymentProcessor;
}
@Produces
PaymentProcessor getPaymentProcessor(@Synchronous PaymentProcessor syncPaymentProcessor,
@Asynchronous PaymentProcessor asyncPaymentProcessor) {
return isSynchronous() ? syncPaymentProcessor : asyncPaymentProcessor;
}
73
Qualifieur @Default

Rappel: un bean a au moins un Qualifieur.

74
Si aucun qualifieur n’est écrit explicitement,
c’est comme si il y avait le qualifieur @Default
Qualifieur @Any

Quel est le qualifieur du bean qui sera injecté ?
@Inject PaymentProcessor paymentProcessor;

Comment dire: « n’importe quel bean » ?
Qualifieur @Any
@Inject @Any PaymentProcessor paymentProcessor;

75
il y a de grandes chances pour que ce point d’injection soit
ambiguë  Exception
Qualifieur avec membre

Une annotation avec membre:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Synchronous {
PaymentMethod value();
}
ici on utilise une énumeration pour aggréger plusieurs qualifieurs en un seul
public enum PaymentMethod { CHEQUE, CB, CASH; }
@PayBy(CHEQUE)
public class PayByCheckBean {...}
ce bean correspond
pour ce point d’injection
@Inject @PayBy(CHEQUE) PayByCheckBean pbcb;
76
Exercice5

Vérifiez dans votre application, avec un qualifieur
@Number qui a un membre qui est une énumeration:
ALEATOIRE, MAX
77
Qualifieur avec membre
annotation @Nonbinding

Un membre d’une annotation qui ne doit pas servir à
restreindre les beans injectables
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Synchronous {
PaymentMethod value();
@Nonbinding String comment() default "";
}
78
Sert:
-soit à proposer un commentaire (comme ici)
-soit à choisir le bean au moment de l’execution
(en utilisant une Producer method et l’introspection java)
Plusieurs qualifieurs
@Inject @PayBy(CHEQUE) @Asynchronous PayByCheckBean pbcb;
Seuls les beans qui ont TOUS les qualifieurs
sont injectables
@Inject @PayBy(CHEQUE) PayByCheckBean pbcb;
Tous les beans qui ont AU MOINS ce qualifieur
sont injectables
79
Alternatives

Un bean peut être déclaré être une implémentation alternative:
@Alternative @Synchronous @Asynchronous
public class MockPaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
Injectable pour @Synchronous
Injectable pour @Asynchronous

Désactivées par défaut, on peut choisir une alternative à utiliser au moment du
déploiement en le spécifiant dans le descripteur META-INF/beans.xml
<beans
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/beans_1_0.xsd">
<alternatives>
<class>org.mycompany.mock.MockPaymentProcessor</class>
</alternatives>
</beans>
80
Exercice6
²

Ecrivez un bean MockGame, alternatif qui étend Game et
redéfinit les méthodes:




getMaxNumber() : résultat toujours égal à 0
getRandomNumber() : résultat toujours égal à 0
Activez cette classe alternative dans beans.xml
Observez les deux résultats différents dans le navigateur
81
Exercice6
²


Ça ne fonctionne pas, pourquoi ?
Un bean alternatif remplace un bean seulement pour les
points d’injection,




Pas dans les expressions EL
Si ce bean contient des méthodes producers, ces méthodes ne
sont pas remplacées
Pour remplacer complètement un bean:
@Alternative @Specialize
Essayez avec MockGame
82
Programmatic lookup

Dans certaines situations, l’injection n’est pas le meilleur
moyen d’obteinur une référence contextuelle avec une
combinaison spécifique d’un type et de qualifieurs




Si le type du bean ou les qualifieurs varient dynamiquement au moment
de l’execution, ou
Selon le déploiement, il peut ne pas y avoir de combinaison
type/qualifieurs acceptable
si on veut itérer sur les beans d’un certain type...
Dans ces situations, on peut injecter une instance de l’objet
paramétré Instance
@Inject Instance<PaymentProcessor> paymentProcessorSource;
83
Programmatic lookup

Si exactement un bean correspond : get()
@Inject @PayBy(CHEQUE) Instance<PaymentProcessor> paymentProcessorSource;
PaymentProcessor paymentProcessor = paymentProcessorSource.get();

Sinon : iterator()
@Inject @Any Instance<PaymentProcessor> paymentProcessorSource;
for(PaymentProcessor p : paymentProcessorSource) {
...
}
84
Programmatic lookup

On peut spécifier des qualifieurs au point d’injection
@Inject @PayBy(CHEQUE) Instance<PaymentProcessor> paymentProcessorSource;

Ou spécialiser par la suite dynamiquement :
@Inject @Any Instance<PaymentProcessor> paymentProcessorSource;
méthode select(Annotation ... qualifiers)

Attention, on doit obtenir une instance de notre qualifieur,
une annotation est une interface,
on peut donc pas juste écrire new Asynchronous() par exemple.
On peut utiliser la classe utilitaire AnnotationLiteral<Asynchronous>...
paymentProcessorSource.select(new AnnotationLiteral<Asynchronous>(){});

85
Attention, ça ne n’est pas utilisable pour une qualifieur avec membre
L’objet InjectionPoint

Certains objets dépendent de l’endroit où ils sont
injectés pour faire ce qu’ils doivent faire..



86
le log doit connaître la classe de l’objet où il est
l’injection d’un paramètre HTTP dépend du nom du paramètre
qui a été spécifié au point d’injection
l’injection du résultat d’une expression EL dépend de
l’expression spécifiée au point d’injection
L’objet InjectionPoint

Exemple du log:

habituellement:
Logger log = Logger.getLogger(MyClass.class.getName());

Avec CDI il suffit d’écrire une petite Producer method:
class LogFactory {
@Produces Logger createLogger(InjectionPoint injectionPoint) {
return Logger.getLogger(injectionPoint
.getMember(). getDeclaringClass().getName());
}
}  et on peut alors utiliser dans chaque classe:
@inject Logger log;
87
L’objet InjectionPoint

Exemple du paramètre HTTP:

un type de qualifieur avec membre @Nonbinding
@BindingType
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface HttpParam {
@Nonbinding public String value();
}

une petite Producer method
class HttpParams
@Produces @HttpParam("")
String getParamValue(InjectionPoint ip) {
ServletRequest request = (ServletRequest) FacesContext.getCurrentInstance()
.getExternalContext().getRequest();
String value = ip.getAnnotated().getAnnotation(HttpParam.class).value();
return request.getParameter(value);
}
}
88
L’objet InjectionPoint

Exemple du paramètre HTTP:

et c’est parti !
@Inject @HttpParam("username") String uname;
@Inject @HttpParam("password") String pwd;
89
L’objet InjectionPoint
public interface InjectionPoint {
public Type getType();
public Set<Annotation> getQualifiers();
public Bean<?> getBean();
public Member getMember();
public Annotated getAnnotated();
public boolean isDelegate();
public boolean isTransient();
}
90
Exercice7

Au moment où l’application est initialisée:


91
Listez l’ensemble des beans qui ont le qualifieur @Rand
Pour chacun de ces beans, affichez le nom qualifié de leur
classe
4- Portées et Contextes
Portée

Quatre portées définis par CDI:




93
@javax.enterprise.context.RequestScoped
@javax.enterprise.context.SessionScoped
@javax.enterprise.context.ApplicationScoped
@javax.enterprise.context.ConversationScoped
Portée

Dans une application web


94
Chaque requête de servet a accès aux portées actives de type
requête, session et application
Une requête JSF a accès à une portée active de type
Conversation
Portée

Dans Java EE, les portées de type requête et application
sont actives






95
Pendant l’invocation d’une méthode EJB remote
Pendant l’invocation d’une méthode EJB asynchrone
Pendant un EJB timeout
Pendant la réception d’un message par un message-driven bean
Pendant la réception d’un message par un MessageListener
Pendant l’invocation d’un service web
Portée

Les @SessionScoped et @ConversationScoped doivent
être sérialisable.
96
Le contexte Conversation

Similaire au contexte Session, mais:


c’est l’application qui définit le début et la fin
Pour JSF: contient l’état d’un seul onglet d’un navigateur

La conversation représente donc une tâche,
« ce sur quoi l’utilisateur travaille »

Le contexte Conversation est actif pendant une requête
JSF, et par défaut est supprimée à la fin de la requête. Si on
veut la garder, on doit signaler explicitement que la requête
est de type « long-running conversation »
97
Le contexte Conversation

A chaque conversation.begin()
doit correspondre un conversation.end() !
@ConversationScoped
@Named("monBean")
public class OrderBuilder implements Serializable {
private @Inject Conversation conversation;
public Conversation getConversation() {return conversation; }
@PostConstruct
private void postConstruct() {
conversation.begin();
}
}
98
public String destroy() {
conversation.end();
return "page2"; // navigation
}
Long-running conversation !
Arrête la conversation !
Le contexte Conversation

Propagation de la conversation


Automatique pour une requête JSF faces (une soumission de
formulaire JSF), ou une redirection,
pas automatique pour un simple lien, on doit utiliser le
paramètre réservé « cid »
<h:link outcome="/addProduct.xhtml" value="Add Product">
<f:param name="cid" value="#{monBean.conversation.id}"/>
</h:link>
99
Le pseudo-contexte Singleton

Un bean qui sera instancié seulement une fois

Les clients ont une référence directe au bean
Gros problème lors de la sérialisation d’une session ou
d’une conversation !!!

solutions:




100
le bean implémente writeResolve() et readReplace()
le bean est déclaré transient (ne sera pas sérialisé)
le client a une référence de type Instance<X>
Ne pas utiliser Singleton et utiliser Application à la place !
Le pseudo-contexte Dependent



contexte par défaut pour les beans qui n’en déclarent pas
Jamais partagé entre les clients
C’est un objet Dépendant de son client


101
il sera instantié en même temps que son client
il sera détruit en même temps que son client
Le qualifieur @New
@Inject @New Calculator calculator;


Pour obtenir un nouvel objet dépendant
Fonctionne même si un autre contexte a été déclaré pour
Calculator

exemple:
@ConversationScoped
public class Calculator { ... }

ici: deux instances différentes de Calculator
public class PaymentCalc {
@Inject Calculator calculator;
@Inject @New Calculator newCalculator;
}
102
Exercice8




Corrigez les erreurs
Faites en sorte que la conversation soit long-running
Testez sur differents onglets et navigateurs
Quel est le scope de Generator ? Quand un bean de type
Generator est-il créé ? Détruit ?
103
5- Producer methods et
attributes
Objectif des Producer Methods



Si l’objet à injecter n’est pas un bean
Si le type concret de l’objet varie au moment de
l’execution
Si l’objet doit être initialisé de manière complexe
105
Objectif des Producer Methods

exemple: polymorphisme au moment de l’execution
@SessionScoped
public class Preferences implements Serializable {
private PaymentStrategyType paymentStrategy;
...
@Produces @Preferred
public PaymentStrategy getPaymentStrategy() {
switch (paymentStrategy) {
case CREDIT_CARD: return new CreditCardPaymentStrategy();
case CHEQUE: return new CheckPaymentStrategy();
case PAYPAL: return new PayPalPaymentStrategy();
default: return null;
}
}
}
@Inject @Preferred PaymentStrategy paymentStrategy;
106
Objectif des Producer Attributes
Quand c’est très simple

@SessionScoped
public class Preferences implements Serializable {
}
@Produces int randomInt= new Random().nextInt();
@Inject int unNombre;
107
Portée de l’objet produit

Par défaut, l’objet produit par un Producer Method a la
portée @Dependent

On peut modifier ça simplement:
@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy() {
...
}
108
Injection dans une Producer Methods
...
case CREDIT_CARD: return new CreditCardPaymentStrategy();
...

Attention ici on instancie un bean avec new !



Pas injection de dépendance dans CreditCardPaymentStrategy,
Pas d’intercepteur possible
Pour ça il faut laisser le conteneur instancier les beans
 Injection !
@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,
CheckPaymentStrategy cps,
PayPalPaymentStrategy ppps) {
switch (paymentStrategy) {
case CREDIT_CARD: return ccps;
case CHEQUE: return cps;
case PAYPAL: return ppps;
default: return null;
}
} 109
Utilisation de @New
@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps,
@New CheckPaymentStrategy cps,
@New PayPalPaymentStrategy ppps) {
switch (paymentStrategy) {
case CREDIT_CARD: return ccps;
case CHEQUE: return cps;
case PAYPAL: return ppps;
default: return null;
}
}


Un nouvel objet dépendant sera créé et associé au
contexte de la session !
Il ne sera détruit qu’à la fin de la session
110
Utilisation de @Disposes

Certains objets renvoyés par un Producer Method
doivent être détruits proprement
@Produces @RequestScoped Connection connect(User user) {
return createConnection(user.getId(), user.getPassword());
}
 méthode de destruction dans la même classe qu’où est
définie la méthode de production !
void close(@Disposes Connection connection) {
connection.close();
}
111
6- Intercepteurs
Intercepteurs

Existent dans Java EE 5, définis dans la spécification
JSR 318 - Java Interceptors 1.1
public class TracingInterceptor {
@AroundInvoke
public Object logCall(InvocationContext context) throws Exception{
System.out.println("Invoking method: " + context.getMethod());
return context.proceed();
System.out.println(« Finished invoking method: " + context.getMethod());
}
}
@Interceptors(TracingInterceptor.class, ...)
@Stateless
public class HelloWorldBean implements HelloWorld {
public void sayHello() {
System.out.println("Hello!");
}
}
113
Intercepteurs


Existent dans Java EE 5, définis dans la spécification JSR
318 - Java Interceptors 1.1
mais contre-intuitif !



On spécifiait directement la classe de l’intercepteur dans l’EJB !
On spécifiait directement l’ordre des intercepteurs dans l’EJB !
CDI améliore cette spécification

114
approche pour lier un intercepteur à un bean est basée sur des
annotations plutôt que explicitement.
Intercepteurs

Intercepter une méthode
public class TransactionInterceptor {
@AroundInvoke
public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}
Intercepter un callback du cycle de vie
public class DependencyInjectionInterceptor {
@PostConstruct
public void injectDependencies(InvocationContext ctx) { ... }
}
Intercepter une méthode timeout
public class TransactionInterceptor {
@AroundInvoke
public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
} 115
API de InvocationContext
public interface InvocationContext {
// savoir des choses sur l’objet intercepté
public Object getTarget();
// si c’est un composant EJB avec un timout
public Object getTimer();
// savoir des choses sur la méthode interceptée
public Method getMethod();
public Object[] getParameters();
public void setParameters(Object[] params);
// permet de passer des informations au prochain intercepteur
public Map<String, Object> getContextData();
// passer la main au prochain intercepteur,
// en bout de chaîne: exécuter la méthode interceptée
public Object proceed() throws Exception;
}
116
Binding d’intercepteur

Avec CDI, une annotation annotée @InterceptorBinding
@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {}

Ensuite on peut dire qu’un objet est transactionnel
@Transactional
public class ShoppingCart { ... }

Ou juste une méthode
public class ShoppingCart {
@Transactional public void checkout() { ... }
}
117
Implémentation de l’intercepteur


Un intercepteur annoté avec @Intercepter et notre
InterceptorBinding @Transactional
Peut utiliser l’injection de dépendance
@Transactional @Interceptor
public class TransactionInterceptor {
@Resource UserTransaction transaction;
}
@AroundInvoke
public Object manageTransaction(InvocationContext ctx) throws Exception { ... }

Il peut y avoir plusieurs intercepteurs du même type de
binding
118
Activation des intercepteurs

Par défaut les intercepteurs sont desactivés
on doit les activer dans META-INF/beans.xml


spécifie l’ordre des intercepteurs
permet de choisir lors du déploiement les intercepteurs à
utiliser
<beans
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/beans_1_0.xsd">
<interceptors>
<class>org.mycompany.myapp.TransactionInterceptor</class>
</interceptors>
</beans>
119
Bindings d’Intercepteurs avec membre

Idem que pour les beans:

si le membre n’est pas annoté @Nonbinding, les membres
doivent correspondre pour qu’il y ait interception
@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {
boolean requiresNew() default false;
}
@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Secure {
@Nonbinding String[] rolesAllowed() default {};
}
120
Plusieurs intercepteurs bindings

Plusieurs intercepteurs pour un bean:
@Secure(rolesAllowed="admin") @Transactional
public class ShoppingCart { ... }

Un intercepteur avec plusieurs bindings
@Transactional @Secure @Interceptor
public class TransactionalSecureInterceptor { ... }
public class ShoppingCart {
@Transactional @Secure public void checkout() { ... }
}
@Secure
public class ShoppingCart {
@Transactional public void checkout() { ... }
}
121
@Transactional
public class ShoppingCart {
@Secure public void checkout() { ... }
}
@Transactional @Secure
public class ShoppingCart {
public void checkout() { ... }
}
Exercice9


Etudiez l’application numberguess9
Implementez un intercepteur TricheurIntercepteur qui
intercepte toutes les méthodes de Game et Generator et
qui liste tout ce qui se passe dans la console




122
Nom de la classe appelée,
Nom de la méthode appelée
Type et valeur des paramètres
Valeur de retour
7- Décorateurs
Intercepteurs vs. Décorateurs

Les intercepteurs offrent des services orthogonaux à
l’application



124
transactions, sécurité, ...
ils ne connaissent pas la sémantique de l’objet intercepté
ils sont utilisables par une grande variété d’objets
Intercepteurs vs. Décorateurs

Les décorateurs interceptent les invocations pour une
interface java seulement




parfait pour ajouter de la logique métier
connaissent la sémantique de cette interface
moins de généralité qu’un intercepteur
Les intercepteurs et les décorateurs sont
complémentaires
125
Décorateurs

Exemple:


public interface Account {
public BigDecimal getBalance();
public User getOwner();
public void withdraw(BigDecimal amount);
public void deposit(BigDecimal amount);
}
les grosses transactions doivent être écrites dans un log
Le boulot parfait pour un décorateur
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
...
}
126
Décorateurs

Un décorateur






annotée @Decorator
implémente l’interface décorée
définit les méthodes qu’qu’on doit intercepter
peut utiliser l’injection de dépendance
peut être une classe abstraite !
Les intercepteurs sont appelés AVANT les décorateurs
127
Décorateurs
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
@Inject @Delegate @Any Account account;
@PersistenceContext EntityManager em;
public void withdraw(BigDecimal amount) {
...
}
}
public void deposit(BigDecimal amount);
...
}
128
Objet délégué @Delegate
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
@Inject @Delegate @Any Account account;
@PersistenceContext EntityManager em;

public void withdraw(BigDecimal amount) {
...
}
Les décorateurs ont un point d’injection pour l’objet délégué
du même type que l’objet décoré
void
deposit(BigDecimal amount);
public
annoté
@Delegate

}
}
129
...
Objet délégué

Un décorateur peut appeler n’importe quelle méthode
de l’objet décoré !
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
@Inject @Delegate @Any Account account;
@PersistenceContext EntityManager em;
public void withdraw(BigDecimal amount) {
account.withdraw(amount);
if ( amount.compareTo(LARGE_AMOUNT)>0 ) {
em.persist( new LoggedWithdrawl(amount) );
}
}
public void deposit(BigDecimal amount);
account.deposit(amount);
if ( amount.compareTo(LARGE_AMOUNT)>0 ) {
em.persist( new LoggedDeposit(amount) );
}
}
130
}
Binding

Un decorateur est associé à tout bean tel que:


Le type du point d’injection est un des types du bean
Le bean a tous les qualifiers declarés au point d’injection
@Inject @Delegate @Any Account account;
décore tous les beans qui implément Account
@Inject @Delegate @Foreign @Saving Account account;
décore seulement les beans qui implément Account
et qui ont les qualifieurs @Foreign et @Saving
131
Activation des décorateurs

Par défaut les décorateurs sont désactivés
on doit les activer dans META-INF/beans.xml


spécifie l’ordre des décorateurs
permet de choisir lors du déploiement les décorateurs à
utiliser
<beans
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/beans_1_0.xsd">
<decorators>
<class>org.mycompany.myapp.LargeTransactionDecorator</class>
</decorators>
</beans>
132
Exercice10


Sur la base de l’application numberguess9
Implementez un décorateur TricheurDecorator pour être
sûr que le nombre à chercher est en réalité entre 1 et 5
133
8- Evènements
Rappel: le patron de conception classique
observateur/observable
déjà dans le patron de conception classique,
les producteurs d’évènements sont découplés des observateurs
135
Evènements dans CDI

Les producteurs d’évènements lèvent des évènements qui
sont passés aux observeurs par le conteneur
136
CDI vs. observateur/observable

Les atouts de CDI:



137
Dans CDI les observateurs sont découplés des
producteurs
Les observateurs peuvent spécifier une collection de
« sélecteurs » pour limiter l’ensemble de notifications
d’évènements qu’ils reçoivent
Les observateurs peuvent être notifiés immédiatement, ou
après la fin de la transaction.
Objet évènement


Comme dans le patron de conception classique
N’importe quel objet java
+ peut avoir des qualifieurs
Permet aux observateurs de spécifier un sous-ensemble
des évènements qu’il observe
138
Observateur

Un observateur est une méthode de bean avec un
paramètre annoté @Observes
public void onAnyDocumentEvent(@Observes Document document) { ... }


le paramètre d’évènement est document
l’observateur peut spécifier des qualifieurs pour
restreindre les évènements qu’il observe
(ci-dessus, par défaut, @Default)
public void onAnyDocumentEvent(@Observes @Updated Document document) { ... }
public void onAnyDocumentEvent(@Observes @Any Document document) { ... }

L’observateur peut avoir d’autres paramètres
(ce sont des points d’injection)
public void onAnyDocumentEvent(@Observes Document document, User user) { ... }
139
Producteurs d’évènements

Les producteurs d’évènement lèvent des évènements en
utilisant l’interface paramétrée Event, obtenue par
injection
@Inject @Any Event<Document> documentEvent;

Pour lever un évènement:
documentEvent.fire(document);
140
Producteurs d’évènements
@Inject @Any Event<Document> documentEvent;
documentEvent.fire(document);
Produit un évènement sans qualifieur
@Inject @Updated Event<Document> documentEvent;
documentEvent.fire(document);
Produit un évènement avec le qualifieur @Updated
@Inject @Any Event<Document> documentEvent;
documentEvent.select(new AnnotationLiteral<Updated>(){}).fire(document);
Produit un évènement avec le qualifieur @Updated
141
Méthode observateur conditionnelle

Par défaut, si aucune instance d’un observateur existe
dans le contexte courant, le conteneur en crée une.
Si on ne veut pas,
public void refreshOnDocumentUpdate(
@Observes(notifyObserver = IF_EXISTS) @Updated Document d) { ... }

Un bean @Dependent ne peut pas être un
observateur conditionnel (il ne serait jamais appelé) !
142
Qualifieur d’évènement avec membre

Un qualifieur d’évènements peut avoir un membre
@Qualifier
@Target({PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface Role {
RoleType value();
}

La valeur du membre sert à limiter les évènements passés à
l’observeur Si le membre n’est pas annoté
@Nonbinding
public void adminLoggedIn(@Observes @Role(ADMIN) LoggedIn event) { ... }
143
Qualifieur d’évènement avec membre

La valeur du membre peut être définie statiquement
@Inject @Role(ADMIN) Event<LoggedIn> loggedInEvent;
loggedInEvent.fire(document);

Ou dynamiquement :
1.
On écrit une sous-classe abstraite de AnnotationLiteral
abstract class RoleBinding
extends AnnotationLiteral<Role>
implements Role {}
2.
Le producteur d’évènements passe une instance de cette classe au
select()
documentEvent.select(new RoleBinding() {
public void value() { return user.getRole(); }
}).fire(document);
144
Observateurs transactionnels
public void refreshCategoryTree(
@Observes(during = AFTER_SUCCESS) CategoryUpdateEvent event) { ... }





IN_PROGESS observers are called immediately (default)
AFTER_SUCCESS observers are called during the after completion
phase of the transaction, but only if the transaction completes successfully
AFTER_FAILURE observers are called during the after completion
phase of the transaction, but only if the transaction fails to complete
successfully
AFTER_COMPLETION observers are called during the after
completion phase of the transaction
BEFORE_COMPLETION observers are called during the before
completion phase of the transaction
145
Exercice11


Sur la base de l’application numberguess9
Faites en sorte que Game et Generator lancent des
évènements et implémentez un ou plusieurs écouteurs de
ces évènements pour trace dans la console, et pouvoir
avoir la réponse au jeu
146
9- Stéréotypes
Stéréotypes


Un stéréotype est une annotation annotée @Stereotype
Regroupe un ensemble de comportements génériques
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
...
public @interface Action {}
148
Portée par défaut

Un stéréotype peut définir une portée par défaut pour
les beans qui le déclarent
@RequestScoped
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
public @interface Action {}
@Action
public class LoginAction { ... }
Portée Requête
@Dependent @Action
public class DependentScopedLoginAction { ... }
149
Portée Dependent
Intercepteurs

Et si on a toute une catégorie de beans qui ont les
mêmes Intercepteurs ?
utiliser un Stéréotype !

@RequestScoped
@Transactional(requiresNew=true)
@Secure
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
public @interface Action {}
150
nos interceptor bindings
Nom EL par défaut

Et si on a toute une catégorie de beans qui doivent avoir
un nom EL ?


utiliser un Stéréotype !
ce sera un nom EL par défaut
@RequestScoped
@Transactional(requiresNew=true)
@Secure
@Named
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
public @interface Action {}
151
Alternatives

Et si on a toute une catégorie de beans alternatifs à
activer ?


Tous les activer un par un dans le fichier de déploiement
META-INF/beans.xml ?
NON: utiliser un stéréotype !
@Alternative
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
public @interface AlternativeAction {}
152
Le stéréotype Model

CDI définit un stéréotype standard, @Model, à utiliser
dans les applications Web...
@Named
@RequestScoped
@Stereotype
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface Model {}

153
... à la place d’un JSF managed bean
10- Amélioration de Java EE
avec CDI
Injection de dépendance dans Java EE


ça existe, mais très souvent utilise des chaînes de
caractères
On peut utiliser CDI pour définir des ressources
proprement
155
Définir une ressource

Une ressource est un objet disponible dans
l’environnement Java EE




156
JDBC Datasource, JMS Queues,Topics
and ConnectionFactorys, JavaMail Sessions et autres
ressources transactionnelles,
JPA EntityManagers et EntityManagerFactorys,
remote EJBs, et
services web
Un bean producteur de ressources

Ressource= données JEE + données CDI
@Produces @WebServiceRef(lookup="java:app/service/Catalog")
Catalog catalog;
@Produces @Resource(lookup="java:global/env/jdbc/CustomerDatasource")
@CustomerDatabase Datasource customerDatabase;
@Produces @PersistenceContext(unitName="CustomerDatabase")
@CustomerDatabase EntityManager customerDatabasePersistenceContext;
@Produces @PersistenceUnit(unitName="CustomerDatabase")
@CustomerDatabase EntityManagerFactory customerDatabasePersistenceUnit;
@Produces @EJB(ejbLink="../their.jar#PaymentService")
PaymentService paymentService;
157
Et ainsi...




Un bean ResourcesProducer avec la liste des ressources
pour le deploiement normal
Un bean ResourcesProducer annoté @Alternative avec la
liste des ressources pour le deploiement de test1
Un bean ResourcesProducer annoté @Alternative avec la
liste des ressources pour le deploiement de test2
...
158
Enfin

On peut utiliser les ressources avec @Inject

plus propre, moins de code à changer si besoin
@Inject Catalog catalog;
@Inject @CustomerDatabase Datasource customerDatabase;
@Inject @CustomerDatabase EntityManager customerDatabasePersistenceContext;
@Inject @CustomerDatabase EntityManagerFactory customerDatabasePersistenceUnit;
@Inject PaymentService paymentService;
159
Context and Dependency Injection
Maxime Lefrançois ([email protected]),
M2 MIAGE Casablanca 2012-2013
Téléchargement