PolyJavaBeans.doc (état du 02/10/06 à 15:48)
Masters pro 2
ème
année de Luminy
Présentation de la technologie JavaBeans
Henri Garreta – Octobre 2006
Table des matières
1.
Approche 2
2.
Constructeurs 3
3.
Evénements 3
3.1.
Objets événements 4
3.2.
Auditeurs d’événements 4
3.3.
Sources d’événements 4
3.4.
Evénements et threads multiples 5
3.5.
Exemple 5
4.
Adaptateurs 6
4.1.
Réflexion 6
4.2.
Adaptateurs génériques 7
5.
Propriétés 8
5.1.
Principe 8
5.2.
Propriétés indicées 9
5.3.
Propriétés liées 9
5.4.
Propriétés contraintes 11
5.5.
Introspection 12
6.
Persistance 13
6.1.
Flux d’entrée-sortie 13
6.2.
Sérialisation des objets 13
6.3.
Sérialisation explicite 15
6.4.
Objets « externalisables » 16
6.5.
Instanciation de beans sérialisés 16
7.
Archives jar 17
8.
Quelques références 18
Présentation de la technologie JavaBeans
2
1. Approche
Il n’est pas facile de donner une définition précise et concise d’un bean Java (ou grain – sans doute de café…). On se
contente habituellement du point de départ suivant :
Un bean Java est un composant logiciel réutilisable qui peut être manipulé visuellement dans un outil de
construction de programmes.
Les beans sont souvent des composants visuels (par exemple, tous les objets
java.awt.Component
, c’est-à-dire tous
les composants AWT et Swing, sont des beans), mais cela n’est pas une obligation ; un bean peut assurer une tâche qui
ne requiert pas une interface avec l’utilisateur, et rester donc invisible.
Ce qui est essentiel est que les beans sont destinés à être assemblés pour constituer des applications. Cela se fait
souvent à l’aide d’outils visuels de construction de programmes, mais ce n’est pas la seule manière, les beans se prêtent
également très bien à être utilisés dans des programmes écrits de manière classique.
La technologie JavaBean est entièrement incluse dans les spécifications du langage et de la plate-forme Java : d’une
part, l’écriture d’un bean ne demande aucun concept ou élément syntaxique nouveau ; d’autre part, son utilisation ne
requiert aucune bibliothèque ni extension particulière. Il n’existe pas de classe
Bean1
, les beans ne forment pas une
hiérarchie de classes, ni même une API : tout objet conforme à certaines règles peut s’appeler un bean.
Trois notions fondamentales de la technologie JavaBean :
Règles de dénomination. Un petit nombre de règles d’écriture et de « nommage » des méthodes doivent être
respectées lorsqu’on écrit un bean. Elles permettent, aussi bien à un lecteur humain qu’à un outil de dévelop-
pement, de reconnaître et de manipuler les caractéristiques d’un bean (c.-à-d. ses propriétés – sortes de variables
« très » publiques -, méthodes et événements), sans avoir à en connaître l’implémentation.
Réflexion. Elément important de Java, le mécanisme de la réflexion (cf. section 4.1, page 6) permet à un outil de
développement d’inspecter les objets durant l’exécution, de connaître et analyser les noms de leurs membres,
d’accéder aux valeurs des variables et d’appeler les méthodes. La réflexion permet à des beans qui se rencontrent
durant l’exécution de faire presque tout ce qui aurait été possible s’ils avaient été assemblés durant la compilation.
Persistance. Il est possible en Java de « geler » un objet existant, avec son état courant, et de le ranger dans un
fichier en vue de le réactiver ultérieurement. Par exemple, cela permet de fixer les propriétés d’un bean durant le
développement, de sorte que son initialisation au moment de l’exécution se réduira au rechargement du bean
sérialisé. De plus, cela offre un mécanisme original pour instancier (i.e. allouer et initialiser) un bean : cloner un
bean sérialisé.
Les principaux éléments de Java que les beans mettent en œuvre sont les suivants :
Evénements. La communication entre beans (a priori développés indépendamment les uns des autres) est assurée
par le mécanisme des événements. Une manière d’attacher deux beans A et B consiste à enregistrer B comme
« auditeur » (listener) d’événements dont A est la source ; cela établit une voie de communication de A vers B.
Propriétés. L’état d’un bean est défini par les valeurs de propriétés. En programmation « à la main », chaque
propriété se manifeste par un couple de méthodes get<Prop> et set<Prop>. Dans un outil de développement, elles
apparaissent sur des feuilles de propriétés qui en rendent graphiques la consultation et la modification.
Définir B comme valeur d’une propriété de A est une autre manière d’attacher deux beans A et B.
Sérialisation. Autant que possible, l’état d’un bean peut être sauvegardé (on dit sérialisé) dans un fichier,
totalement ou partiellement, en vue de sa désérialisation ultérieure.
Archivage. Un bean se compose généralement de plusieurs classes. L’utilitaire
jar
permet de réunir celles-ci en un
unique fichier, compressé, utilisable par la machine Java grâce à un « manifeste » qui en décrit le contenu.
1
Il y a bien une classe
java.beans.Beans
(notez le pluriel), mais elle n’est pas destinée à avoir des instances. C’est
plutôt une bibliothèque, entièrement faite de membres statiques. Le rôle de cette classe, comme des autres éléments des
paquets
java.beans
et
java.beans.beancontext
, est d’aider le programmeur dans la conception et l’utilisation
des beans.
Présentation de la technologie JavaBeans
3
2. Constructeurs
Un bean doit avoir un constructeur sans arguments
2
.
C’est la seule contrainte stricte que supportent les beans : tout objet qui a un constructeur sans arguments peut giti-
mement s’appeler bean (mais il ne sera peut-être pas très utile). D’autre part, ce n’est pas une obligation, mais il est
fortement recommandé de permettre aux beans d’être sérialisés. Ainsi, par exemple, voici une « version bean » du
concept de nombre entier :
public class Entier implements java.io.Serializable {
private int valeur = 0;
public int getValeur() {
return valeur;
}
public void setValeur(int valeur) {
this.valeur = valeur;
}
}
Cela semble bizarre, en définissant un objet pour représenter un nombre, de ne pas écrire un constructeur permettant de
donner la valeur de ce nombre. C’est que le constructeur d’un bean n’est pas un élément très important.
En effet, en gle nérale la « vraie » construction d’un bean ne se produit pas au sein de l’application qui utilise le
bean, durant l’exécution, mais auparavant, dans l’outil de développement qui a servi à assembler l’application. Dans cet
outil, un certain éditeur de propriétés aura permis de définir l’état du bean à partir d’un ensemble de valeurs utiles. A la
fin du développement, le bean, dans l’état ainsi défini et ensemble avec les autres composants de l’application, aura été
« congelé » (sérialisé) dans un fichier.
Ultérieurement, quand l’application sera exécutée et que le bean deviendra nécessaire, il sera simplement « décongelé »
(désérialisé) et il aura tout de suite les valeurs intéressantes définies durant le développement. Cette désérialisation d’un
bean sérialisé, distincte de la construction ou instanciation habituelle, s’appelle instanciation de bean.
3. Evénements
La technologie JavaBeans utilise, sans ajout ni modification, le modèle événementiel de Java, introduit dans le langage
lors de la parution de la version 1.1.
Un événement commence à exister quand un objet S construit une instance E d’une certaine sous-classe de la classe
EventObject
et lenvoie à un ou plusieurs objets A
i
qui ont été préalablement inscrits comme devant être « avertis »
chaque fois qu’une telle chose se produirait. On dit que E est l’événement, S est la source de l’événement et que les A
i
sont les auditeurs (listener) de l’événement E pour la source S. Au lieu d’envoi on dit plutôt notification d’un
événement ; cela consiste dans le fait que la source S appelle une certaine méthode, avec E pour argument, sur chacun
des auditeurs A
i
.
Source d’événements
Auditeur d’événements
Objet
événement
notifie un événement
s’enregistre comme auditeur
Dans les interfaces graphiques ce mécanisme est principalement emplopour notifier la détection des actions de
l’utilisateur et provoquer les réactions appropriées de la part des objets adéquats : S est souvent un composant
graphique et E rend compte d’un événement extérieur (produit dans le monde réel) qui affecte S, comme un clic avec la
2
Ne pas oublier que tel est le cas d’une classe dans laquelle on n’a explicité aucun constructeur.
Présentation de la technologie JavaBeans
4
souris, une frappe au clavier, etc. Dans le cas des beans ce mécanisme est généralisé et devient le principal moyen de
communication entre beans.
Les événements sont regroupés en catégories éventuellement réduites à un seul élément – d’événements voisins.
Exemples, tirés de
awt
:
MouseEvent
(événements liés à la souris),
KeyEvent
(événements en rapport avec le clavier)
ActionEvent
(qui contient un seul événement, signalant l’actionnement d’un bouton), etc.
Dire qu’un objet O peut être auditeur d’une catégorie <C> d’événements c’est dire que O possède toutes les méthodes
par lesquelles les événements de <C> sont notifiés. En Java, cela se fait en déclarant que O implémente une certaine
interface, définie à cet effet. L’interface correspondant à une catégorie
<
C
>Event
se nomme
<
C
>Listener
.
Exemples :
MouseListener
,
KeyListener
,
ActionListener
, etc.
Les auditeurs d’un événement doivent être enregistrés auprès de la source de tels événements. Cela se fait par un appel
de la méthode
add<
C
>Listener(<
C
>Listener
X
)
, qui incorpore X dans la liste des auditeurs à prévenir lorsque
<C> se produit. Exemples :
addMouseListener
,
addKeyListener
,
addActionListener
, etc.
3.1. Objets événements
Un objet événement est instance d’une classe, spécifique de l’événement en question. Par convention, le nom de cette
classe est de la forme
<
C
>Event
. Exemple :
PropertyChangeEvent
.
Cette classe doit être sous-classe de la classe
java.util.EventObject
, dont l’unique constructeur se présente :
public EventObject(Object source)
Il en découle qu’un événement comporte toujours la férence de l’objet qui en est la source. Exemple de constructeur
pour l’événement donné en exemple :
public PropertyChangeEvent(Object source,
String propertyName, Object oldValue, Object newValue);
3.2. Auditeurs d’événements
Notifier un événement c’est appeler une méthode, spécifique de l’événement ou d’une catégorie d’événements, avec
pour argument l’événement en question. Par exemple, un bean notifie que la valeur d’une de ses propriétés a changé en
appelant la méthode :
public void propertyChange(PropertyChangeEvent evt);
L’ensemble des méthodes de notification des événements d’une catégorie donnée sont rassemblées en une interface
(qui, de fait, définit la catégorie en question). Cette interface doit être sous-interface de l’interface
java.util.
EventListener
. Exemple :
public interface PropertyChangeListener extends EventListener {
void propertyChange(PropertyChangeEvent evt);
}
Un auditeur (listener) d’une catégorie d’événements est un objet auquel doivent être notifiés les événements en
question lorsqu’ils surviennent.
Deux conditions pour qu’un objet L soit auditeur des évènements d’une catégorie <C>, dont la source est un objet S :
on doit enregistrer L, auprès de S, comme auditeur des événements <C>. Cela se fait par une expression telle que :
S
.add<
C
>Listener(L);
pour cela, l’objet L doit implémenter l’interface
<
C
>Listener
.
3.3. Sources d’événements
Pour qu’on objet soit source d’événements d’une certaine catégorie <C> il doit offrir les deux méthodes
public void add<
C
>Listener(<
C
>Listener obj);
public void remove<
C
>Listener(<
C
>Listener obj);
Inversement, repérer dans une classe les méthodes ayant les noms et les signatures précédentes permet de découvrir les
événements dont les objets de ce type peuvent être la source.
Présentation de la technologie JavaBeans
5
3.4. Evénements et threads multiples
Un auditeur peut recevoir des notifications d’événements faites par des méthodes appelées dans plusieurs threads
différents. Il faut donc prendre des mesures, pour éviter aussi bien des comportements incohérents que des blocages du
programme (étreinte mortelle). Des principes à observer :
il est recommandé que les méthodes de notification, dans les auditeurs d’événements, soient synchronisées (c’est-
à-dire qualifiées
synchronized
), de manière à ce que les éventuelles réactions à un me événement notifié
depuis plusieurs sources prennent place les unes après les autres ;
l’objet source d’un événement ne doit pas être verrouillé lorsqu’il appelle une méthode de notification sur un
auditeur de cet événement car la réaction de l’auditeur pourrait être l’appel d’une méthode de l’objet source c’est
un cas fréquent – et le blocage serait alors probable ;
pour notifier un événement, l’objet source doit parcourir la liste des auditeurs ; or, la réaction d’un auditeur peut
être de modifier cette liste (par exemple, suite à l’événement, l’auditeur s’enlève de la liste, ou bien lui ajoute un
nouvel auditeur) ; il y a alors un risque que le parcours devienne incohérent. En programmant l’opération « notifier
un événement à tous les auditeurs » il faut donc prendre soin de parcourir non pas la liste des auditeurs, mais un
clone de cette liste, produit à cette occasion : voyez
notifyTemperatureChange
dans l’exemple suivant.
3.5. Exemple
Beaucoup des exemples suivants sont extraits du livre de R. Englander (cf. § 8. Références).
Un objet
PointChaud
possède constamment une température courante. Lorsque celle-ci change, il prévient tous les
objets
Thermostat
concernés par ce phénomène.
Un objet
TempChangeEvent
est la notification d’un changement de température. Fichier
TempChangeEvent.java
:
public class TempChangeEvent extends EventObject {
protected double temp;
public TempChangeEvent(Object source, double temp) {
super(source);
this.temp = temp;
}
public double getTemperature() {
return temp;
}
}
Un objet qui prétend pouvoir jouer le rôle d’un thermostat doit implémenter l’interface
TempChangeListener
. Fichier
TempChangeListener.java
:
public interface TempChangeListener extends java.util.EventListener {
void tempChange(TempChangeEvent evt);
}
Un point chaud doit gérer la liste des thermostats qui lui ont été posés. Fichier
PointChaud.java
:
public class PointChaud {
protected double tempCour = 18;
private Vector tempChangeListeners = new Vector();
public double getTemperatureCourante() {
return tempCour;
}
public void setTemperatureCourante(double temp) {
tempCour = temp;
notifyTemperatureChange();
}
public synchronized void addTempChangeListener(TempChangeListener l) {
if ( ! tempChangeListeners.contains(l))
tempChangeListeners.addElement(l);
}
public synchronized void removeTempChangeListener(TempChangeListener l) {
if (tempChangeListeners.contains(l))
tempChangeListeners.removeElement(l);
}
1 / 18 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !