La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Context and Dependency Injection

Présentations similaires


Présentation au sujet: "Context and Dependency Injection"— Transcription de la présentation:

1 Context and Dependency Injection
Maxime Lefrançois M2 MIAGE Casablanca

2 Introduction

3 Questions rébarbatives
Pour un objet A ... 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 ?

4 Context and Dependency Injection = CDI (JSR-299)
CDI est un modèle riche de programmation couplage faible avec typage fort

5 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)

6 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)

7 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: leur cycle de vie, leur implémentation concrete leur modèle de threading

8 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

9 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

10 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, ...

11 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

12 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

13 Beans – typage fort Un objet avec état lié à un contexte = un bean
couplage faible avec typage fort 7. l’utilisation du fichier descripteur est limitée pour les informations qui dépendent du déploiement  META-INF/beans.xml

14 Notion de Bean Quels beans on connaît ? C’est quoi un bean ?

15 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: injection de ressources callbacks de cycle de ...) des intercepteurs (définis dans le bean = couplage fort !!!) c’est quoi les propriétés d’un Managed Bean ?

16 Exercice 1 Pour commencer, une petite application pour vérifier quelques notions des Servlets et JSF2… Corrigez les erreurs !

17 Notion de Bean Quels beans on connaît ? les javabeans les Managed Bean
les EJB Session Beans / Message-driven Beans Les beans selon Spring Les beans selon Seam ...

18 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 (ou un producteur de beans)

19 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); } 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;         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 ?

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;         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();    } } Les paramètres du constructeur seront injectés est-ce que c’est un bean ? OUI. Le conteneur va appeler le constructeur et injecter d’autres beans dans les paramètres du constructeur.

22 Un exemple d’injection
On écrit donc une classe pour traduire un document en entier public class TextTranslator {    private SentenceParser sentenceParser;    private Translator sentenceTranslator;         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

23 Un exemple d’injection
Exemple de Managed Bean qui utilise une instance injectée de TextTranslator public class TranslateController {    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;    } }

24 Utiliser CDI

25 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 Ça crée simplement un fichier descripteur META-INF/beans.xml Avec Glassfish: 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, … Suivre la procédure: US/html/environments.html#d0e5225

26 Projet Java SE avec CDI On utilise l’implémentation de référence: Weld
Le jar: weld-se-core.jar Ou avec Maven: Est-ce qu’on doit écrire une classe principale avec un main ? <dependency> <groupId>org.jboss.weld.se </groupId> <artifactId>weld-se </artifactId> <version>CHOISIR LA DERNIERE FINALE</version> </dependency>

27 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 Écouteur de l’évènement ContainerInitialized On récupère les paramètres de la ligne de commande par injection @Singleton public class HelloWorld { @Parameters List<String> parameters) {        System.out.println("Hello " + parameters.get(0));    } }

28 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)

29 Introduction à CDI

30 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

31 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: Un ensemble non vide de types Un ensemble non vide de qualifieurs

32 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> {    ... }

33 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: Permet de désambiguiser l’objet à injecter, sans utiliser une chaîne de caractères @Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, PARAMETER, FIELD})

34 Type, qualifieur et injection de dépendance
Pour ce point d’injection: 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 { ... }

35 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

36 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 ?

37 Contexte (scope) Le contexte d’un bean définit le cycle de vie de ses instances Un contexte est représenté par une …

38 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

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 ex: 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>

40 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 ex: 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> Propriété lineItems !

41 Nom EL (EL= Expression Language)
Valeur par défaut: class ShoppingCart implements Serializable {   public List<Item> getLineItems() {...} } <h:dataTable value="#{???.lineItems}" var="item">    ... </h:dataTable> Comme dans Exercice1

42 Alternatives Un bean peut être déclaré être une implémentation 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

43 Intercepteurs Existent dans Java EE 5
import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; public class TracingInterceptor {         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!");     } }

44 Intercepteurs Existent dans Java EE 5, 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 !

45 Intercepteurs Dans CDI: annotation de lien à un (groupe d’intercepteurs) @InterceptorBinding @Inherited @Target( { TYPE, METHOD }) @Retention(RUNTIME) 2. L’intercepteur déclare cette annotation: class TransactionInterceptor { ... } 3. On applique cet aspect à un bean: class ShoppingCart implements Serializable { ... } 4. On active les intercepteurs et on définit leur ordre dans le fichier descripteur MEAT-INF/beans.xml

46 Quelles classes sont des beans ?
(Injectables, décorables, interceptables, ...) Les Managed Beans Les EJB Session Beans Les Producer Methods Les Producer Fields

47 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)

48 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 n’est pas un composant EJB (un session bean...) n’implémente pas javax.enterprise.inject.spi.Extension a un constructeur approprié : soit un constructeur sans paramètres un constructeur

49 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 A UN ENTITY BEAN

50 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)

51 Session Bean ou Managed Bean ?
Dans CDI, On peut injecter: un session bean dans un autre session bean, Un managed dans un session bean, Un session bean dans un managed bean, ... Dans CDI, 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 Session Bean ou Managed Bean ?
Dans CDI, On peut injecter: un session bean dans un autre session bean, Un managed dans un session bean, Un session bean dans un managed bean, ... Dans CDI, 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 ? Quand on a besoin des services offerts par le conteneur d’EJB !

53 Producer Methods Comment injecter un int au hasard entre 1 et 100 ?

54 Producer Methods Comment injecter un int au hasard entre 1 et 100 ?
@ApplicationScoped public class RandomNumberGenerator {        private Random random = new Random(System.currentTimeMillis());               return random.nextInt(100);    }     }

55 Producer Methods Comment injecter un int au hasard entre 1 et 100 ?
C’est cette méthode qui sera appelée pour injecter une instance d’un bean avec le type int et le @ApplicationScoped public class RandomNumberGenerator {        private Random random = new Random(System.currentTimeMillis());               return random.nextInt(100);    }     } Un constructeur @Inject public int rand, ...) { ... } Un attribut Des méthodes int rand; ...

56 Producer Methods Comment choisir au moment de l’execution quelle implémentation d’un type de bean on veut instantier et injecter ?

57 Producer Methods Une Producer Method
Comment choisir au moment de l’execution quelle implémentation d’un type de bean on veut instantier et injecter ? Une Producer Method

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 ?

59 Producer Methods Une Producer Method
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

60 Producer Fields Un raccourci pour les cas simples, plus simple que les Producer Methods: Les Producer Fields public class Shop { }

61 Exercice4 Ecrivez une producer method et/ou un producer field pour l’entier aléatoire et l’entier max Etudiez l’enchaînement des appels de méthode Vérifiez que le bean Game est bien associé à une session

62 Injection

63 Points d’injection d’un bean
Maintenant on a des beans, on peut les injecter.

64 Points d’injection d’un bean
Constructeur d’un autre bean public class Checkout {             private final ShoppingCart cart;         public Checkout(ShoppingCart cart) {       this.cart = cart;    } } Un bean ne peut avoir qu’un seul constructeur

65 Points d’injection d’un bean
Méthode d’initialisation public class Checkout {             private ShoppingCart cart;    void setShoppingCart(ShoppingCart cart) {       this.cart = cart;    }      } Un bean peut avoir plusieurs méthodes d’initialisation

66 Points d’injection d’un bean
Injection d’attribut public class Checkout {          ShoppingCart cart; } Un bean peut avoir plusieurs méthodes d’initialisation

67 Points d’injection d’un bean
Le conteneur appelle le constructeur du bean (celui par défaut ou celui 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 appelée

68 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); }

69 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...

70 Qu’est-ce qui est injecté ?
Si plusieurs beans correspondent pour le point d’injection ? On peut utiliser un Qualifieur Les Qualifieurs peuvent avoir des membres On peut combiner plusieurs Qualifieurs Certains beans peuvent être des Alternatives

71 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})

72 Qualifieurs Qualifieur pour annoter: Un bean
@Synchronous public class SynchronousPaymentProcessor implements PaymentProcessor {    public void process(Payment payment) { ... } }

73 Qualifieurs Qualifieur pour annoter: Un point d’injection
@Inject    this.syncPaymentProcessor = syncPaymentProcessor; } @Inject    this.syncPaymentProcessor = syncPaymentProcessor; } @Produces    return isSynchronous() ? syncPaymentProcessor : asyncPaymentProcessor; }

74 Qualifieur @Default Rappel: un bean a au moins un Qualifieur.
Si aucun qualifieur n’est écrit explicitement, c’est comme si il y avait le

75 Qualifieur @Any Quel est le qualifieur du bean qui sera injecté ?
Comment dire: « n’importe quel bean » ? il y a de grandes chances pour que ce point d’injection soit ambiguë  Exception @Inject PaymentProcessor paymentProcessor; PaymentProcessor paymentProcessor;

76 Qualifieur avec membre
Une annotation avec membre: @Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) 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 PayByCheckBean pbcb;

77 Exercice5 Vérifiez dans votre application, avec un qualifieur @Number qui a un membre qui est une énumeration: ALEATOIRE, MAX

78 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}) PaymentMethod value(); @Nonbinding String comment() default ""; } 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)

79 Plusieurs qualifieurs
@Inject PayByCheckBean pbcb; Seuls les beans qui ont TOUS les qualifieurs sont injectables Tous les beans qui ont AU MOINS ce qualifieur sont injectables PayByCheckBean pbcb;

80 Alternatives Un bean peut être déclaré être une implémentation alternative: 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 public class MockPaymentProcessor implements PaymentProcessor {    public void process(Payment payment) { ... } } Injectable Injectable <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>

81 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

82 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: Essayez avec MockGame

83 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;

84 Programmatic lookup Si exactement un bean correspond : get()
Sinon : iterator() Instance<PaymentProcessor> paymentProcessorSource; PaymentProcessor paymentProcessor = paymentProcessorSource.get(); Instance<PaymentProcessor> paymentProcessorSource; for(PaymentProcessor p : paymentProcessorSource) { ... }

85 Programmatic lookup On peut spécifier des qualifieurs au point d’injection Ou spécialiser par la suite dynamiquement : 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>... Attention, ça ne n’est pas utilisable pour une qualifieur avec membre Instance<PaymentProcessor> paymentProcessorSource; Instance<PaymentProcessor> paymentProcessorSource; paymentProcessorSource.select(new AnnotationLiteral<Asynchronous>(){});

86 L’objet InjectionPoint
Certains objets dépendent de l’endroit où ils sont injectés pour faire ce qu’ils doivent faire.. 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

87 L’objet InjectionPoint
Exemple du log: habituellement: Avec CDI il suffit d’écrire une petite Producer method: et on peut alors utiliser dans chaque classe: Logger log = Logger.getLogger(MyClass.class.getName()); class LogFactory {       return Logger.getLogger(injectionPoint getMember(). getDeclaringClass().getName());     } } @inject Logger log;

88 L’objet InjectionPoint
Exemple du paramètre HTTP: un type de qualifieur avec une petite Producer method @BindingType @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) } class HttpParams    String getParamValue(InjectionPoint ip) {       ServletRequest request = (ServletRequest) FacesContext.getCurrentInstance() getExternalContext().getRequest(); String value = ip.getAnnotated().getAnnotation(HttpParam.class).value();       return request.getParameter(value);    } }

89 L’objet InjectionPoint
Exemple du paramètre HTTP: et c’est parti !

90 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(); }

91 Exercice7 Au moment où l’application est initialisée:
Listez l’ensemble des beans qui ont le Pour chacun de ces beans, affichez le nom qualifié de leur classe

92 4- Portées et Contextes

93 Portée Quatre portées définis par CDI:
@javax.enterprise.context.RequestScoped @javax.enterprise.context.SessionScoped @javax.enterprise.context.ApplicationScoped @javax.enterprise.context.ConversationScoped

94 Portée Dans une application web
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

95 Portée Dans Java EE, les portées de type requête et application sont actives 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

96 Portée doivent être sérialisable.

97 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 »

98 Le contexte Conversation
A chaque conversation.begin() doit correspondre un conversation.end() ! @ConversationScoped  @Named("monBean") public class OrderBuilder implements Serializable { public Conversation getConversation() {return conversation; }     private void postConstruct() {       conversation.begin();    }    public String destroy() {       conversation.end(); return "page2"; // navigation } } Long-running conversation ! Arrête la conversation !

99 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>

100 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: 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 !

101 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 il sera instantié en même temps que son client il sera détruit en même temps que son client

102 Le qualifieur @New Pour obtenir un nouvel objet dépendant
Pour obtenir un nouvel objet dépendant Fonctionne même si un autre contexte a été déclaré pour Calculator exemple: ici: deux instances différentes de Calculator @ConversationScoped public class Calculator { ... } public class PaymentCalc { }

103 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 ?

104 5- Producer methods et attributes

105 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

106 Objectif des Producer Methods
exemple: polymorphisme au moment de l’execution @SessionScoped public class Preferences implements Serializable {    private PaymentStrategyType paymentStrategy;    ...    public PaymentStrategy getPaymentStrategy() {        switch (paymentStrategy) {            case CREDIT_CARD: return new CreditCardPaymentStrategy();            case CHEQUE: return new CheckPaymentStrategy();            case PAYPAL: return new PayPalPaymentStrategy();            default: return null;        }     } }

107 Objectif des Producer Attributes
Quand c’est très simple @SessionScoped public class Preferences implements Serializable {     randomInt= new Random().nextInt(); } @Inject int unNombre;

108 Portée de l’objet produit
Par défaut, l’objet produit par un Producer Method a la On peut modifier ça simplement: public PaymentStrategy getPaymentStrategy() {    ... }

109 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 ! 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;    }  }

110 Utilisation    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

111 Utilisation de @Disposes
Certains objets renvoyés par un Producer Method doivent être détruits proprement  méthode de destruction dans la même classe qu’où est définie la méthode de production !    return createConnection(user.getId(), user.getPassword()); }    connection.close(); }

112 6- Intercepteurs

113 Intercepteurs Existent dans Java EE 5, définis dans la spécification JSR Java Interceptors 1.1 public class TracingInterceptor {     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, public class HelloWorldBean implements HelloWorld {           public void sayHello() {         System.out.println("Hello!");     } }

114 Intercepteurs Existent dans Java EE 5, définis dans la spécification JSR 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 approche pour lier un intercepteur à un bean est basée sur des annotations plutôt que explicitement.

115 Intercepteurs Intercepter une méthode
Intercepter un callback du cycle de vie Intercepter une méthode timeout public class TransactionInterceptor {    public Object manageTransaction(InvocationContext ctx) throws Exception { ... } } public class DependencyInjectionInterceptor {    public void injectDependencies(InvocationContext ctx) { ... } } public class TransactionInterceptor {    public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }

116 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; }

117 Binding d’intercepteur
Avec CDI, une annotation Ensuite on peut dire qu’un objet est transactionnel Ou juste une méthode @InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) @Transactional public class ShoppingCart { ... } public class ShoppingCart { }

118 Implémentation de l’intercepteur
Un intercepteur annoté et notre Peut utiliser l’injection de dépendance Il peut y avoir plusieurs intercepteurs du même type de binding public class TransactionInterceptor {    public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }

119 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>

120 Bindings d’Intercepteurs avec membre
Idem que pour les beans: si le membre n’est pas les membres doivent correspondre pour qu’il y ait interception @InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME)    boolean requiresNew() default false; } @InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) }

121 Plusieurs intercepteurs bindings
Plusieurs intercepteurs pour un bean: Un intercepteur avec plusieurs bindings public class ShoppingCart { ... } public class TransactionalSecureInterceptor { ... } public class ShoppingCart { } @Transactional public class ShoppingCart { } @Secure public class ShoppingCart { } public class ShoppingCart {    public void checkout() { ... } }

122 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 Nom de la classe appelée, Nom de la méthode appelée Type et valeur des paramètres Valeur de retour

123 7- Décorateurs

124 Intercepteurs vs. Décorateurs
Les intercepteurs offrent des services orthogonaux à l’application transactions, sécurité, ... ils ne connaissent pas la sémantique de l’objet intercepté ils sont utilisables par une grande variété d’objets

125 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

126 Décorateurs Exemple: Le boulot parfait pour un décorateur
les grosses transactions doivent être écrites dans un log Le boulot parfait pour un décorateur public interface Account {    public BigDecimal getBalance();    public User getOwner();    public void withdraw(BigDecimal amount);    public void deposit(BigDecimal amount); } @Decorator public abstract class LargeTransactionDecorator       implements Account {    ... }

127 Décorateurs Un décorateur
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

128 Décorateurs @Decorator public abstract class LargeTransactionDecorator       implements Account {         public void withdraw(BigDecimal amount) {       ...    }         public void deposit(BigDecimal amount);       ...    } }

129 Objet délégué @Delegate
@Decorator public abstract class LargeTransactionDecorator       implements Account {         public void withdraw(BigDecimal amount) {       ...    }         public void deposit(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é

130 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 {         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) );       }    } }

131 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 décore tous les beans qui implément Account @Saving Account account; décore seulement les beans qui implément Account et qui ont les

132 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>

133 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

134 8- Evènements

135 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

136 Evènements dans CDI Les producteurs d’évènements lèvent des évènements qui sont passés aux observeurs par le conteneur

137 CDI vs. observateur/observable
Les atouts de CDI: 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.

138 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

139 Observateur Un observateur est une méthode de bean avec un paramètre 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 L’observateur peut avoir d’autres paramètres (ce sont des points d’injection) Document document) { ... } Document document) { ... } User user) { ... }

140 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 Pour lever un évènement: documentEvent.fire(document);

141 Producteurs d’évènements
documentEvent.fire(document); Produit un évènement sans qualifieur documentEvent.fire(document); Produit un évènement avec le documentEvent.select(new AnnotationLiteral<Updated>(){}).fire(document); Produit un évènement avec le

142 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, Un ne peut pas être un observateur conditionnel (il ne serait jamais appelé) ! public void refreshOnDocumentUpdate(

143 Qualifieur d’évènement avec membre
Un qualifieur d’évènements peut avoir un membre La valeur du membre sert à limiter les évènements passés à l’observeur Si le membre n’est pas annoté @Nonbinding @Qualifier @Target({PARAMETER, FIELD}) @Retention(RUNTIME)    RoleType value(); }

144 Qualifieur d’évènement avec membre
La valeur du membre peut être définie statiquement Ou dynamiquement : On écrit une sous-classe abstraite de AnnotationLiteral Le producteur d’évènements passe une instance de cette classe au select() loggedInEvent.fire(document); abstract class RoleBinding     extends AnnotationLiteral<Role>     implements Role {} documentEvent.select(new RoleBinding() {    public void value() { return user.getRole(); } }).fire(document);

145 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

146 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

147 9- Stéréotypes

148 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) ...

149 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) @Action  public class LoginAction { ... } Portée Requête public class DependentScopedLoginAction { ... } Portée Dependent

150 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) nos interceptor bindings

151 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)

152 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)

153 Le stéréotype Model CDI définit un stéréotype à utiliser dans les applications Web... ... à la place d’un JSF managed bean @Named  @RequestScoped  @Stereotype  @Target({TYPE, METHOD})  @Retention(RUNTIME) 

154 10- Amélioration de Java EE avec CDI

155 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

156 Définir une ressource Une ressource est un objet disponible dans l’environnement Java EE JDBC Datasource, JMS Queues, Topics and ConnectionFactorys, JavaMail Sessions et autres ressources transactionnelles, JPA EntityManagers et EntityManagerFactorys, remote EJBs, et services web

157 Un bean producteur de ressources
Ressource= données JEE + données CDI Catalog catalog; @CustomerDatabase Datasource customerDatabase; @CustomerDatabase EntityManager customerDatabasePersistenceContext; @CustomerDatabase EntityManagerFactory customerDatabasePersistenceUnit; PaymentService paymentService;

158 Et ainsi... Un bean ResourcesProducer avec la liste des ressources pour le deploiement normal Un bean ResourcesProducer avec la liste des ressources pour le deploiement de test1 Un bean ResourcesProducer avec la liste des ressources pour le deploiement de test2 ...

159 Enfin On peut utiliser les ressources avec @Inject
plus propre, moins de code à changer si besoin @Inject Catalog catalog; @Inject PaymentService paymentService;

160 Context and Dependency Injection
Maxime Lefrançois M2 MIAGE Casablanca


Télécharger ppt "Context and Dependency Injection"

Présentations similaires


Annonces Google