Développement de beans session singleton
Créez une classe d'implémentation pour un bean session singleton introduit par la spécification Enterprise JavaBeans (EJB) 3.1.. Le conteneur EJB initialise une seule instance de bean session singleton et cette instance est partagée par tous les clients. Dans la mesure où une seule instance est partagée par tous les clients, les beans session singleton ont un cycle de vie spécial et une sémantique à accès concurrentiel.
Avant de commencer
Pourquoi et quand exécuter cette tâche
public interface Configuration {
Object get(String name);
void set (String name, Object value);
}
@Singleton
public class ConfigurationBean implements Configuration {
private Map<String, Object> settings = new HashMap<String, Object>();
public Object get(String name) {
return settings.get(name);
}
public void set(String name, Object value) {
settings.put(name,value);
}
}
Comme pour les autres types de beans enterprise, vous pouvez déclarer des métadonnées pour les beans session singleton dans le descripteur de déploiement au lieu d'utiliser des annotations, par exemple :
<?xml version="1.0"?>
<ejb-jar
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/ejb-jar_3_1.xsd"
version="3.1"
>
<enterprise-beans>
<ejb-name>ConfigurationBean</ejb-name>
<business-local>com.ibm.example.Configuration</business-local>
<ejb-class>com.ibm.example.ConfigurationBean</ejb-class>
<session-type>Singleton</session-type>
</enterprise-beans>
</ejb-jar>
Procédure
- Codez les méthodes d'initialisation et de destruction, en examinant
leur relation avec vos options pour définir le contexte de transaction. Pendant l'initialisation, l'instance est créée, une injection de dépendance
se produit, et les rappels d'intercepteur de cycle de vie PostConstruct sont démarrés. Les rappels
d'intercepteur de cycle de vie PreDestroy sont démarrés pour un bean session singleton
lorsque que l'application qu'il contient est arrêtée.
Il peut être utile d'effectuer des activités transactionnelles pendant les rappels d'intercepteur de cycle de vie PostConstruct et PreDestroy. C'est pour cette raison que les rappels d'intercepteur de cycle de vie d'un bean session singleton ont un contexte de transaction bien défini. Les valeurs de contexte de transaction suivantes sont similaires aux méthodes @Timeout : seules REQUIRED (par défaut), REQUIRES_NEW et NOT_SUPPORTED peuvent être utilisées et REQUIRED est convertie en REQUIRES_NEW.
Les attributs de transaction sont reconnus uniquement lorsqu'ils sont définis dans des méthodes d'intercepteur de cycle de vie dans la classe bean. Le même contexte de transaction est utilisé pour tous les intercepteurs de cycle de vie. L'exemple suivant montre un bean session singleton avec des attributs de transaction définis pour les rappels d'intercepteur de cycle de vie PostConstruct et PreDestroy.
@Singleton public class ConfigurationBean implements Configuration { @PostConstruct @TransactionAttribute(REQUIRED) // valeur par défaut ; spécifié ici à titre d'illustration public void initialize() { // ... } @PreDestroy @TransactionAttribute(NOT_SUPPORTED) public void destroy() { // ... } // ... }
Au lieu d'utiliser une annotation, vous définissez les mêmes métadonnées en utilisant le descripteur de déploiement XML. Si vous définissez des attributs de transaction dans le descripteur de déploiement XML, les métadonnées de l'annotation @Transaction sont ignorées. L'exemple suivant utilise le descripteur de déploiement XML pour définir les mêmes métadonnées que dans l'exemple précédent.
<assembly-descriptor> <container-transaction> <method> <ejb-name>ConfigurationBean</ejb-name> <method-name>initialize</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> <container-transaction> <method> <ejb-name>ConfigurationBean</ejb-name> <method-name>destroy</method-name> </method> <trans-attribute>NotSupported</trans-attribute> </container-transaction> </assembly-descriptor>
- Sauf autrement spécifié, l'instance de bean session singleton
est habituellement initialisée à la première utilisation du bean via une de ses vues client
qui est la même que celle des autres beans session. Utilisez l'annotation @Startup ou le descripteur de déploiement XML correspondant pour marquer un bean comme bean de démarrage. Le marquage d'un bean singleton comme bean de démarrage implique que le conteneur EJB doit exécuter la méthode PostConstruct avant de permettre l'exécution des demandes de client externe envoyées à l'application.
Une méthode PostConstruct dans un bean singleton peut créer un temporisateur EJB, ajouter un message à une file d'attente ou un sujet JMS, appeler une méthode EJB asynchrone ou lancer d'autres mécanismes asynchrones qui appellent un EJB.
Toutefois, pour éviter un interblocage, la méthode PostConstruct ne doit pas attendre l'exécution d'un temporisateur EJB, l'appel d'un bean géré par message ou la fin d'une méthode EJB asynchrone.
Les développeurs d'applications peuvent placer la logique métier dans les méthodes PostConstruct de ces instances de singleton de démarrage pour effectuer des tâches qui doivent être réalisées avant que le conteneur ne démarre un quelconque travail du client, comme le pré-chargement des caches ou l'initialisation d'un travail asynchrone à l'intérieur de l'application.
L'exemple suivant illustre un bean session singleton avec une initialisation de démarrage :
@Singleton @Startup public class ConfigurationBean implements Configuration { @PostConstruct public void initialize() { // 1. Créez la table d'une base de données si elle n'existe pas. // 2. Initialisez les paramètres à partir de la table d'une base de données. // 3. Chargez un cache. // 4. Initialisez un travail asynchrone (par exemple, un travail vers une file d'attente de messagerie ou pour // appeler des méthodes de bean session asynchrone. } // ... }
Au lieu d'utiliser une annotation, vous définissez les mêmes métadonnées en utilisant le descripteur de déploiement XML. Spécifiez la valeur true pour marquer ce bean singleton comme singleton de démarrage. Inversement, indiquez false pour remplacer l'annotation @Startup si elle existe dans le fichier classe.
<session> <ejb-name>ConfigurationBean</ejb-name> <init-on-startup>true</init-on-startup> </session>
- Déterminez si la méthode d'initialisation du bean session singleton
session a une dépendance implicite sur un autre bean session singleton.
Si une telle dépendance existe, utilisez les métadonnées de dépendance pour rendre la dépendance explicite. Le conteneur garantit que les beans session singleton de dépendance sont initialisés avant leurs beans dépendants et qu'ils ne sont pas détruits après la destructions de leurs beans dépendants. L'exemple suivant montre un bean session singleton avec des métadonnées de dépendance :
@Singleton public class DatabaseBean { @PostConstruct public void initialize() { // Create database tables. } } @Singleton @DependsOn({"DatabaseBean"}) public class ConfigurationBean implements Configuration { @PostConstruct public void initialize() { // Initialize settings from a database table. } // ... }
En outre, vous pouvez créer des dépendances intermodule en utilisant la syntaxe ejb-link module.jar#bean. Les dépendances circulaires ne sont pas prises en charge et provoquent l'échec d'une application.
Au lieu d'utiliser une annotation, vous définissez les mêmes métadonnées en utilisant le descripteur de déploiement XML. Si vous définissez des métadonnées de dépendance dans le descripteur de déploiement XML, les métadonnées de l'annotation @DependsOn sont ignorées.
<session> <ejb-name>ConfigurationBean</ejb-name> <depends-on> <ejb-name>DatabaseBean</ejb-name> </depends-on> </session>
- Décidez d'utilisez l'accès concurrentiel géré par conteneur ou l'accès concurrentiel
géré par bean. Les annotations @Lock et @AccessTimeout ne sont pas disponibles
quand l'accès concurrentiel géré par bean est utilisé.
Vous pouvez implémenter l'annotation @ConcurrencyManagement annotation uniquement dans la classe bean session singleton. Elle ne peut pas être utilisée dans la classe qu'elle étend ni dans une classe supérieure dans l'arborescence d'héritage de classes.
L'exemple de code suivant illustre un singleton avec un accès concurrentiel géré par bean :@Singleton @ConcurrencyManagement(BEAN) public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); synchronized public Object get(String name) { return settings.get(name); } synchronized public void set(String name, Object value) { settings.put(name, value); } }
Au lieu d'utiliser une annotation, vous définissez les mêmes métadonnées en utilisant le descripteur de déploiement XML. Si les métadonnées sont définies dans le descripteur de déploiement XML et en utilisant l'annotation @ConcurrencyManagement, la valeur doit correspondre pour que l'application n'échoue pas. L'exemple suivant utilise le descripteur de déploiement XML pour définir les mêmes métadonnées que dans l'exemple précédent.
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrency-management-type>Bean</concurrency-management-type> </session>
Le conteneur n'effectue aucun verrouillage pour chaque méthode appelée. Par contre, le bean en cours est responsable des verrouillages requis. Dans l'exemple, le fournisseur de bean a choisi d'implémenter les méthodes en utilisant le mot clé synchronisé. Ceci est pris en charge pour les beans session singleton avec une concurrence gérée par bean, et non pour les autres types de composant EJB. Le fournisseur de bean n'est pas tenu d'utiliser le mot clé synchronisé pour fournir la concurrence. Par exemple, le fournisseur de bean peut utiliser la classe java.util.concurrent.locks.ReentrantReadWriteLock qui se trouve dans JDK version 5 ou ultérieure.
La sémantique de verrouillage requise par la spécification EJB 3.1 pour l'accès concurrentiel géré par conteneur, correspond au comportement de la classe java.util.concurrent.locks.ReentrantReadWriteLock class.
- Si vous utilisez l'accès concurrentiel géré par conteneur, servez-vous de la notation @Lock
pour gérer l'accès concurrentiel des méthodes. L'exemple de code suivant illustre un singleton avec un accès concurrentiel géré par conteneur.
@Singleton public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); @Lock(READ) public Object get(String name) { return settings.get(name); } public void set(String name, Object value) { settings.put(name, value); } }
Au lieu d'utiliser une annotation, vous définissez les mêmes métadonnées en utilisant le descripteur de déploiement XML. Si les métadonnées sont définies dans le descripteur de déploiement XML et en utilisant l'annotation @Lock, la valeur doit correspondre pour que l'application n'échoue pas. L'exemple suivant utilise le descripteur de déploiement XML pour définir les mêmes métadonnées que dans l'exemple précédent.
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>get</method-name> </method> <lock>Read</lock> </concurrent-method> </session>
L'exemple illustre également l'annotation d'une méthode avec @Lock(READ) pour indiquer que le conteneur a besoin d'un verrou en lecture lorsque la méthode est démarrée. Quand une méthode est annotée avec @Lock, cela remplace l'annotation @Lock qui est spécifiée au niveau de la classe. Quand il n'y a pas d'annotation @Lock au niveau de la classe, l'annotation par défaut est un verrou en écriture. Dans l'exemple, l'annotation @Lock(READ) de la méthode se substitue à l'annotation par défaut de verrou en écriture au niveau de la classe. Lorsqu'il n'y a pas d'annotation au niveau de la méthode et qu'il n'y a pas d'annotation au niveau de la classe, l'annotation par défaut de verrou en écriture est utilisé par le conteneur.
Comme le verrou en lecture est requis pour la plupart des méthodes, utilisez @Lock(READ) au niveau de la classe pour indiquer que le conteneur doit obtenir un verrou en lecture pour toutes les méthodes métier de cette classe. Pour les méthodes qui requièrent un verrou en écriture, annotez ces méthodes avec @Lock(WRITE) pour indiquer que cela se substitue au verrou en lecture qui était spécifié au niveau de la classe.
L'exemple suivant illustre cette technique :
@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); public Object get(String name) { return settings.get(name); } @Lock(WRITE) public void set(String name, Object value) { settings.put(name, value); } }
L'annotation @Lock s'applique uniquement aux méthodes déclarées dans la même classe que l'annotation. Pour une classe donnée, les métadonnées pour @Lock ne sont jamais héritées d'une classe supérieure dans l'arborescence d'héritage de classe. Au lieu d'utiliser une annotation au niveau de la classe, les mêmes métadonnées peuvent être définies dans le descripteur de déploiement XML en utilisant le nom de méthode spécial * qui fait correspondre toutes les méthodes.
- Si vous utilisez un accès concurrentiel géré par conteneur, servez-vous de la notation @AccessTimeout
pour limiter le temps d'attente de la méthode pour obtenir un verrou. L'exemple de code suivant illustre les délais d'attente d'accès concurrentiel.
@Singleton public class ConfigurationBean implements Configuration { @Lock(READ) @AccessTimeout(1000) public Object get(String name) { // interroge la base de données } public void set(String name, Object value) { // mets à jour la base de données } }
Si aucune annotation n'est fournie, par défaut la méthode attend l'obtention d'un verrou. Il n'y a pas de limite dans le temps à l'attente nécessaire pour qu'un client obtienne un verrou. Comme rien n'est codé au niveau de la classe, il n'y a pas de limite pour le temps d'attente du verrou pour toutes les méthodes de la classe. Quand l'annotation @AccessTimeout est utilisée et que le conteneur ne peut pas accorder le verrou dans la limite de temps spécifiée, une exception javax.ejb.ConcurrentAccessTimeoutException est envoyée au client. L'annotation @AccessTimeout s'applique uniquement aux méthodes déclarées dans la même classe que l'annotation. Pour une classe donnée, les métadonnées pour @AccessTimeout ne sont jamais héritées d'une classe supérieure dans l'arborescence d'héritage de classe.
Comme pour l'annotation @Lock, vous pouvez également définir l'annotation @AccessTimeout en utilisant le descripteur de déploiement XML et si vous utilisez le descripteur de déploiement XML, les métadonnées de l'annotation @AccessTimeout sont ignorées. L'exemple suivant utilise le descripteur de déploiement XML pour définir les mêmes métadonnées que dans l'exemple précédent.
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>get</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>1000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
- Il est important de savoir que le codage XML de concurrent-methodType suit les trois styles décrits dans la spécification EJB de composition XML pour les éléments de méthode container-transaction.
Notez que les éléments lock et access-timeout sont facultatifs. Les trois styles sont décrits comme suit :
Le style 1 utilise le nom de méthode spécial * pour appliquer le type de verrou, le délai d'accès ou les deux à toutes les méthodes de gestion du bean défini.
<!-- Exemple : Style 1 --> <concurrent-method> <method> <method-name>*</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
Le style 2 permet de faire référence à une méthode de gestion avec un nom donné et de l'affecter du type de verrou défini, du délai d'accès ou des deux. Si le nom de méthode est surchargé, ce qui implique que plusieurs méthodes portent le même nom, mais ont des signatures différentes, toutes les méthodes portant ce nom ont le type ou le délai d'accès défini ou les deux. Le style 2 est prioritaire sur le style 1.
<!-- Exemple : Style 2 --> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
Le style 3 permet de faire référence à une méthode distincte qui correspond au nom de méthode donné et qui a une signature qui correspond aux paramètres de méthode listés. Le style 3 est prioritaires sur les styles et 2.
<!-- Exemple : Style 3 --> <concurrent-method> <method> <method-name>businessMethod</method-name> <method-params> <method-param>long</method-param> <method-param>int</method-param> </method-params> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
Si le XML du style 1 est utilisé pour définir un type de verrou, toutes les annotations @Lock dans le bean sont ignorées. Cela s'applique également d'accès. Si le XML du style 1 est utilisé pour définir un délai d'accès, toutes les annotations @AccessTimeout dans le bean sont ignorées.
- Il est important de savoir que les annotations @Lock et @AccessTimeout sont traitées indépendamment de l'une de l'autre, comme le code de descripteur de déploiement XML de chaque annotation.
L'implémentation de concept offre divers avantages. Cette séparation de type de verrou et de délai d'accès permet de ne pas affecter négativement le code d'application "black box" en ne vous obligeant pas à connaître le type de verrou. Vous pouvez conserver sans problème le type de verrou et ajuster le délai d'attente uniquement en fonction de votre environnement et éviter ainsi les interblocages ou d'autres problèmes de concurrence.
Supposons que vous disposez d'une application EJB d'un fournisseur et qu'elle subisse des problèmes de délai d'attente suite à la lenteur du système. Vous ne voulez pas changer la logique de verrouillage de peut de créer un interblocage, mais vous voulez changer la valeur de délai d'attente. Vous pouvez modifier le descripteur de déploiement et définir le délai d'attente nécessaire pour les méthodes à modifier.L'exemple suivant montre comment spécifier une simple annotation @Lock(READ) au niveau méthode dans l'implémentation de bean et utiliser le style 2 pour composer XML pour indiquer l'élément acess-timeout 2 000 millisecondes, sans fournir l'élément de verrou facultatif. Vous obtenez une méthode avec un verrou de lecture ayant un délai d'attente de 2 000 millisecondes.
@Singleton public class ConfigurationBean implements Configuration { @Lock(READ) public Object businessMethod(long value) { // ... } // ... }
De même, vous pouvez utiliser une annotation de verrou au niveau de la classe et définir le délai d'attente approprié dans XML en utilisant le style 2, le style 3 ou les deux comme le montre l'exemple suivant.<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { public Object businessMethod(long value) { // ... } public Object businessMethod(long value, int i, Object value) { // ... } public Object businessMethod(long value, int i) { // ... } }
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> <concurrent-method> <method> <method-name>businessMethod</method-name> <method-params> <method-param>long</method-param> <method-param>int</method-param> </method-params> </method> <access-timeout> <timeout>8000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
Dans cet exemple de code, toutes les méthodes nommées “businessMethod” ont un verrou de lecture et un délai d'accès de 2 000 millisecondes. A l'exception de l'instance de la méthode “businessMethod” qui a une signature avec le premier paramètre de type long et le second paramètre de type int, qui a un verrou de lecture, mais un délai d'attente de 8 000 millisecondes.
Le même principe s'applique lorsque le code XML de style 1 est utilisé pour définir un type de verrou, mais pas un délai d'attente. Vous pouvez ajouter un délai d'accès à une méthode spécifique ou à des méthodes en utilisant le style 2 et/ou le style 3 pour obtenir un type de verrou et un délai d'accès spécifiques. L'exemple suivant montre ce point :<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>*</method-name> </method> <lock>Read</lock> </concurrent-method> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
Dans l'exemple suivant, toutes les méthodes de gestion ont un verrou de lecture et la méthode businessMethod a un verrou de lecture et un délai d'accès de 2 000 millisecondes.
Vous pouvez également disposer d'une annotation @Lock au niveau de la classe pour définir le type de verrou de toutes les méthodes et utiliser le style 1 pour composer XML pour définir uniquement le délai d'accès de toutes les méthodes. Examinez l'exemple suivant :@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { public Object businessMethod(long value) { // ... } // ... }
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>*</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
Dans cet exemple, toutes les méthodes de gestion du bean ConfigurationBean ont un verrou de lecture et un délai d'accès de 2 000 millisecondes.
- Veillez à bien comprendre les règles d'héritage des annotations que vous utilisez.
- Evitez le comportement de verrouillage réentrant qui peut se produire, si une
méthode avec un verrou en lecture appelle une méthode avec un verrou en écriture dans le même bean session singleton.
Supposez que la méthode métier d'un bean session singleton provoque directement ou indirectement le démarrage d'une autre méthode métier d'un bean session singleton. Si la première méthode est une méthode de verrou d'écriture, elle peut appeler une autre méthode de gestion du bean session singleton sans autre considération spéciale. Toutefois, vous pouvez implémenter une méthode de verrou de lecture si elle devait appeler une autre méthode métier du même bean session singleton qui est une méthode de verrou d'écriture. Ensuite, une exception javax.ejb.IllegalLoopbackException est émise.
Sous-rubriques
Changer la politique d'attribution de verrous pour les beans de session singleton
Pour tous les beans de session singleton exécutés dans le serveur, l'attribution de verrous d'écriture aux appelants obéit, par défaut, à une politique dite "non équitable" (non-fair). Il est possible de changer ce comportement et d'appliquer une politique d'attribution équitable. Cette procédure s'adresse aux utilisateurs de WebSphere Application Server qui ne souhaitent pas que les appels aux méthodes de leurs beans de session singleton suivent une politique d'attribution de verrous non équitable.Changer la politique d'attribution de verrous pour les beans de session singleton
Pour tous les beans de session singleton exécutés dans le serveur, l'attribution de verrous d'écriture aux appelants obéit, par défaut, à une politique dite "non équitable" (non-fair). Il est possible de changer ce comportement et d'appliquer une politique d'attribution équitable. Cette procédure s'adresse aux utilisateurs de WebSphere Application Server qui ne souhaitent pas que les appels aux méthodes de leurs beans de session singleton suivent une politique d'attribution de verrous non équitable.


http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tejb_ssb
Nom du fichier : tejb_ssb.html