I. Introduction▲
I-A. JMX▲
Issu principalement de la spécification JSR 3 et JSR 255, JMX est un standard développé par JCP (Java Community Process) pour la gestion et le suivi des applications et services. Ce standard définit une architecture de gestion, des design patterns, des API, et des services pour construire des solutions distribuées, dynamiques, et modulaires pour la gestion de ressources de tout type, L'API JMX rend possible la gestion d'équipements logiciels ou matériels allant de simples téléphones à des serveurs en passant par des périphériques et des applications, l'utilisation de la technologie JMX pour gérer les applications et les services augmente leurs flexibilités en rendant les applications plus faciles à installer, à configurer et à maintenir.
Pour être administrables, les ressources logicielles ou matérielles doivent être instrumentées sous la forme de composants appelés MBeans (Managed Beans). Ces composants fournissent une interface d'administration et l'instrumentation nécessaire permettant de contrôler les ressources associées encapsulées dans le MBean. L'interface d'administration définie par JMX doit permettre aux vendeurs de composants de produire des composants administrables et aux vendeurs d'outils d'administration d'utiliser cette interface pour administrer ces composants. Contrairement à SNMP, JMX prend en compte les différents métiers intervenants dans la conception et l'administration d'application.
JMX fait partie du kit de développement Java depuis la version 5.0. Il a subi dans la version 6.0 de très brèves améliorations.
Actuellement, JCP réalise la JSR 262 qui définit un connecteur JMX utilisant les web services, pour permettre une administration native des MBeans. Les clients JMX utilisant ce type de connecteur n'auront pas à être écrits en Java.
I-B. les MBeans▲
Un MBean est un objet Java qui constitue une interface de communication avec un élément logiciel ou physique. Plus précisément, un MBean est un JavaBean respectant les designs patterns lexiques suivants.
1. Le nom de l'interface correspond au nom de la classe du MBean suffixé par la chaîne ''MBean''. Ainsi le nom de l'interface correspondant au MBean de classe X sera XMBean.
2. Pour chaque attribut public représentant la ressource administrée, il doit exister une méthode de type get et/ou set permettant respectivement de lire et/ou de modifier la valeur de cet attribut. Le nom de ces méthodes dépend du nom de l'attribut associé. La déclaration de ces méthodes doit respecter le design pattern lexique suivant :
public
AttrType getAttrName
(
); // "getter"
public
void
setAttrName
(
AttrType val); // "setter"
AttrType peut être n'importe quel type Java, AttrName est sensible à la casse, donc getattr1() et getAttr1() définissent deux attributs différents respectivement : Attr1 et attr1. Si le getter et le setter de l'attribut sont présents, alors l'attribut peut être lu et changé (read-write), si le getter est présent, mais pas le setter alors l'attribut est en lecture seule (read-only), enfin si le setter est présent, mais pas le getter alors l'attribut est en écriture seule (write-only). Si AttrType est boolean, alors le getter peut être défini par le design pattern lexique suivant :
public
boolean
isAttrName
(
);
Un MBean est identifié dans le serveur par son nom d'objet ou ObjectName. Un ObjectName est composé de deux parties, le domaine et les propriétés. Le domaine est une chaine de caractères n'incluant pas le caractère deux-points (:). Si le domaine inclut le caractère étoile (*) ou le point d'interrogation (?), alors l'object name est un pattern. L'étoile (*) signifie n'importe quelle séquence de 0 ou plus caractères, et le point d'interrogation (?) signifie un seul caractère. Les propriétés sont souvent de la forme type=XYZ.
I-C. Activer/Désactiver le MBeanServer▲
I-C-1. Activer l'agent JMX▲
Pour administrer une application Java en utilisant l'API JMX, vous devez faire ceci.
- Activer l'agent JMX (un autre nom du MBeanServer) lors du lancement de l'application. Vous pouvez activer l'agent JMX pour l'administration locale, pour un client JMX s'exécutant sur le même système et aussi pour l'administration distante, pour un client JMX s'exécutant sur un système distant.
- Administrer l'application Java avec un client JMX conforme à la spécification JMX, comme JConsole.
Sous la version 5.0 de Java SE, pour permettre aux clients JMX d'accéder à un agent local, vous devez définir la propriété système com.sun.management.jmxremote au lancement de votre application. Par exemple, pour activer l'agent JMX pour l'application Notepad, vous devez lancer l'application avec la commande suivante.
java -Dcom.sun.management.jmxremote -jar Notepad.jar
Dans Java SE 6, il n'est plus nécessaire de définir cette propriété système. N'importe quelle application lancée dans la plateforme Java SE 6 pourra être administrée en local. Vous n'aurez qu'à exécuter l'application avec la ligne de commande suivante :
java -jar Notepad.jar
Une fois Notepad lancée, un client JMX peut administrer l'application Notepad.
I-C-2. Désactiver l'agent JMX▲
Dans certains cas, ou pour quelques raisons de sécurité, un développeur peut désactiver l'agent JMX au lancement de son application dans la plateforme Java SE 6. Ceci est fait en exécutant l'application avec le paramètre -XX:+DisableAttachMechanism. Par exemple, pour désactiver l'agent JMX pour l'application Notepad, vous devez lancer l'application avec la commande suivante :
java -XX:+DisableAttachMechanism -jar Notepad.jar
I-D. L'API pour interroger le MBeanServer▲
Le serveur de MBean (MbeanServer) joue le rôle d'un référentiel qui maintient une liste de tous les MBeans. Toutes les opérations d'administration appliquées sur un MBean sont effectuées à partir de l'API du MBeanServer. Cette API définit des méthodes permettant :
- D'instancier et d'enregistrer un nouveau MBean dans le serveur. On peut noter que le concepteur d'un MBean peut contrôler la manière dont un MBean est enregistré/déenregistré dans le serveur. Un MBean peut définir des méthodes qui seront appelées avant et après son enregistrement (ou son désenregistrement) ;
- D'accéder aux attributs d'un MBean et d'invoquer ses opérations.
Il existe six méthodes d'accès aux MBeans enregistrés sur un MBeanServer
Object getAttribute
(
ObjectName objname, String attrname);
AttributeList getAttributes
(
ObjectName objname, String[] attrnames);
MBeanInfo getMBeanInfo
(
ObjectName objname);
Object invoke
(
ObjectName objname, String method, Object[] params, String[] signature);
void
setAttribute
(
ObjectName objname, Attribute attribute);
AttributeList setAttributes
(
ObjectName objname, AttributeList attributes);
Remarquons que :
- Le paramètre de type ObjectName référence le nom avec lequel le MBean a été enregistré sur le MbeanServer ;
- Les méthodes getAttribute() et getAttributes() retournent les valeurs des attributs du MBean spécifiés ;
- Les méthodes setAttribute et setAttributes() modifient les valeurs des attributs du MBean spécifiés ;
- La méthode invoke() exécute une opération sur le MBean spécifié ;
- L'objet de type MBeanInfo retourné par la méthode getMBeanInfo() encapsule des métadonnées qui décrivent l'interface du MBean enregistré sous le nom spécifié par ObjectName. La Figure suivante présente la structure statique de ses informations.
Le MBeanServer utilise un MBeanInfo pour implémenter les méthodes d'accès au MBean, le MBeanServer s'assure qu'aucune méthode n'est invoquée et aucun attribut n'est lu ou mis à jour s'il n'est pas décrit dans le MBeanInfo. Un client JMX peut utiliser getMbeanInfo() pour récupérer une description complète de l'interface de gestion du MBean, comme c'est le cas pour JConsole qui utilise MBeanInfo pour afficher des informations sur les MBeans sous forme arborescente.
I-E. JConsole▲
JConsole est un outil de suivi conforme à la spécification JMX (Java Management Extensions). JConsole utilise l'instrumentation de la machine virtuelle Java pour fournir des informations sur les performances et la consommation des ressources des applications en cours d'exécution sur la plateforme Java. L'exécutable de JConsole se trouve dans JDK_HOME/bin, où JDK_HOME est le répertoire où est installé le JDK. Si ce répertoire est dans la variable d'environnement Path, vous pouvez lancer JConsole simplement en tapant JConsole dans la ligne de commande. Sinon, vous devez taper le chemin complet de l'exécutable.
I-F. Survol des MBean présents par défaut▲
Dans l'onglet MBeans de jconsole, on peut trouver des MBeans prédéfinis par la machine virtuelle, ces MBeans peuvent fournir des informations diverses sur l'état de la machine virtuelle (mémoire libre, Heap, nombre de classes chargées, nombre de threads en cours d'exécution, etc.). Ces informations peuvent être utiles dans certains cas de diagnostic ou de maintenance.
I-F-1. Gestion de la mémoire▲
On peut obtenir l'usage actuel de la mémoire heap en consultant la valeur de l'attribut HeapMemoryUsage du MBean Memory.
I-F-2. Gestion des threads▲
Ou obtenir le nombre de threads en cours d'exécution sur la machine virtuelle.
I-F-3. Gestion des niveaux logs▲
Le MBean logging offre la possibilité d'effectuer les tâches suivantes :
- Récupérer le nom du niveau de log associé au loggeur spécifié ;
- Récupérer la liste des loggeurs actuellement enregistrés ;
- Récupérer le nom du père d'un loggeur ;
- Modifier un loggeur spécifique vers le niveau spécifié.
II. Exemple de connexion à un agent JMX▲
II-A. Création d'un connecteur RMI▲
JMXServiceURL url =
new
JMXServiceURL
(
"service:jmx:rmi://localhost/jndi/rmi://localhost:9999/jmxrmi"
);
JMXConnector jmxc =
JMXConnectorFactory.connect
(
url, null
);
MBeanServerConnection mbsc =
jmxc.getMBeanServerConnection
(
);
Le code précédent crée un connecteur RMI client qui est configuré pour se connecter à un connecteur RMI serveur créé par un agent JMX. Comme vous le voyez, on définit l'URL de l'agent. Cela permet au connecteur client de récupérer un stub du connecteur RMI serveur via le registre RMI s'exécutant sur le port 9999 dans la machine locale. Le connecteur client créé est une instance de l'interface JMXConnector en appelant la méthode connect() de la classe JMXConnectorFactory. La méthode connect() est appelée avec comme paramètre l'URL de l'agent JMX distant. Une instance de MBeanServerConnection, nommée mbsc, est créée en appelant la méthode getMBeanServerConnection() de l'instance de JMXConnector appelée jmxc. Le connecteur client est maintenant connecté au MBeanServer créé par l'agent JMX distant, il peut dorénavant enregistrer des MBeans et effectuer des opérations d'une manière transparente sur eux.
II-B. Utilisation d'un proxy pour travailler sur un MBean distant▲
L'utilisation d'un proxy signifie travailler sur un MBean distant, comme si on avait son objet en local, c'est-à-dire pouvoir invoquer ses méthodes comme si l'objet existait en local.
II-B-1. Sous J2SE 5.0▲
La création d'un proxy sous J2SE 5.0 est effectuée par la méthode newProxyInstance de la classe javax.management.MBeanServerInvocationHandler. Cette méthode retourne un objet qui peut être casté vers le type de l'interface du MBean.
Exemple :
HelloMBean proxy =
(
HelloMBean)
MBeanServerInvocationHandler.newProxyInstance
(
mbsc,name,HelloMBean.class
,false
);
En supposant par exemple que HelloMBean est défini comme suit :
public
interface
HelloMBean {
public
void
sayHello
(
);
public
int
add
(
int
x, int
y);
public
String getHelloWord
(
);
public
void
setHelloWord
(
String value);
}
Alors, on peut exécuter :
- proxy.getHelloWord() qui va résulter en un appel de mbsc.getAttribute(name,"HelloWord") ;
- proxy.setHelloWord("bonjour") qui va résulter en un appel de mbsc.setAttribute(name,new Attribute("HelloWord","bonjour")) ;
- proxy.sayHello() qui va résulter en un appel de mbsc.invoke(name,"sayHello",null).
II-B-2. Sous J2SE 6.0▲
La création d'un proxy sous J2SE 6.0 est effectuée par la méthode newMBeanProxy de la classe javax.management.JMX. Cette méthode retourne directement une instance du MBean sans être obligé de faire un casting, ceci est effectué en utilisant les types génériques de Java.
Exemple :
HelloMBean proxy =
JMX.newMBeanProxy
(
mbsc, name, HelloMBean.class
);
Avec HelloMBean définit comme précédemment.
II-C. Utilisation d'un filtre pour récupérer plusieurs MBeans d'un agent JMX▲
Un utilisateur veut dans certains cas, récupérer un ensemble de MBeans répondant à un critère. Cela peut être effectué avec la méthode queryNames() de l'interface MBeanServerConnection. La méthode queryNames() est définie comme suit :
Set<
ObjectName>
queryNames
(
ObjectName name,QueryExp query) throws
IOException
Cette méthode récupère le nom de tous les MBeans, le nom d'un ensemble de MBeans spécifié par pattern matching sur l'ObjectName fourni en paramètre et/ou une requête QueryExp.
Paramètres :
- name - Le pattern du nom d'objet identifiant les noms des MBeans qui doivent être récupérés. Si sa valeur est null alors le nom de tous les MBeans enregistrés sera récupéré ;
- query - L'expression utilisée comme filtre pour sélectionner les MBeans. Si sa valeur est null, aucun filtre ne sera utilisé pour sélectionner les noms des MBeans.
II-C-1. Exemple▲
Set<
ObjectName>
ensemble =
mbsc.queryNames
(
new
ObjectName
(
"Hello:*"
),Query.eq
(
Query.attr
(
"HelloWord"
),Query.value
(
"Bonjour"
)));
La requête précédente permet de récupérer tous les noms d'objets dont le domaine est égal à Hello, et ayant l'attribut HelloWord égal à « Bonjour ». La classe Query fournit une multitude de méthodes pour construire une expression qui servira de filtre pour récupérer les noms des MBeans. parmi ces méthodes on peut citer :
and
(
QueryExp q1, QueryExp q2) // retourne une expression qui est une conjonction de deux autres expressions.
attr
(
String name) // retourne une expression représentant la valeur d'un attribut.
eq
(
ValueExp v1, ValueExp v2) // retourne une expression qui est une égalité de deux autres expressions.
value
(
String val) // retourne une expression représentant un String.
III. Exemple d'administration d'un MBean avec JConsole▲
Depuis la version 5.0 de la plateforme Java 2 Standard Edition, JMX est entièrement intégré dans l'API, et un outil qui s'appelle JConsole est fourni avec le JDK, il permet de gérer des MBeans dans des processus locaux, ou distants en utilisant un connecteur RMI.
Nous allons montrer pas à pas comment se fait l'administration d'une ressource grâce à l'outil JConsole.
III-A. Boite de dialogue de connexion▲
Quand on lance JConsole, on obtient la boite de dialogue de connexion, la boite de dialogue offre deux possibilités, on peut soit se connecter à un processus local ou distant. Dans la capture d'écran suivante, on a trois processus locaux, sms3.jar, appel3.jar, et JConsole lui-même.
Dans notre exemple de démonstration, nous allons administrer un processus local, mais en utilisant une URL distante (avec localhost comme nom de machine).
III-B. Création du MBean et de l'agent JMX▲
III-B-1. Le MBean▲
Le MBean qu'on va utiliser dans cet exemple est défini par la classe et l'interface suivantes :
package
org.sdf;
public
interface
HelloMBean {
public
void
sayHello
(
);
public
int
add
(
int
x, int
y);
public
String getHelloWord
(
);
public
void
setHelloWord
(
String value);
}
package
org.sdf;
public
class
Hello implements
HelloMBean {
private
String helloWord;
public
int
add
(
int
x, int
y) {
return
x +
y;
}
public
String getHelloWord
(
) {
return
helloWord;
}
public
void
sayHello
(
) {
System.out.println
(
helloWord);
}
public
void
setHelloWord
(
String value) {
helloWord =
value;
}
}
Dans l'exemple, on peut constaté que la ressource qu'on va instrumenter a un attribut de type String appelé HelloWord qui peut être lu et modifié (get et set), en plus de cet attribut, on a deux opérations : sayHello() et add(int x,int y).
III-B-2. L'agent JMX▲
L'agent a pour but de faire la liaison entre les MBeans et les applications d'administration. Il réalise le pont entre les deux et se porte garant de la qualité de service.
Concrètement, un agent JMX se compose d'un MBean Server et de l'ensemble des MBeans enregistrés auprès de lui. Il délivre des services que des connecteurs de la couche services distribués appellent. Toutes les opérations effectuées sur un MBean se font au travers d'un agent (un MBean Server).
Notre agent sera un programme Java qui va créer un MBeanServer et enregistrer une instance de la classe Hello dans ce serveur, et créer un connecteur RMI pour ce serveur, afin qu'on puisse s'y connecter avec JConsole en utilisant l'URL fournie.
package
org.sdf;
import
java.lang.management.ManagementFactory;
import
java.rmi.registry.LocateRegistry;
import
javax.management.MBeanServer;
import
javax.management.ObjectName;
import
javax.management.remote.JMXConnectorServer;
import
javax.management.remote.JMXConnectorServerFactory;
import
javax.management.remote.JMXServiceURL;
public
class
Main {
/**
*
@param
args
*/
public
static
void
main
(
String[] args) {
try
{
MBeanServer mbs =
ManagementFactory.getPlatformMBeanServer
(
);
LocateRegistry.createRegistry
(
9999
);
ObjectName name =
new
ObjectName
(
"Hello:type=HelloObject"
);
Hello h =
new
Hello
(
);
h.setHelloWord
(
"Bonjour"
);
mbs.registerMBean
(
h, name);
JMXServiceURL url =
new
JMXServiceURL
(
"service:jmx:rmi://localhost/jndi/rmi://localhost:9999/server"
);
JMXConnectorServer cs =
JMXConnectorServerFactory
.newJMXConnectorServer
(
url, null
, mbs);
cs.start
(
);
System.out.println
(
"ecoute ...."
);
while
(
true
) {
System.out.println
(
h.getHelloWord
(
));
Thread.sleep
(
3000
);
}
}
catch
(
Exception e) {
}
}
}
III-C. Connexion à l'agent▲
Après avoir compilé et exécuté notre agent, on lance jconsole, et on entre l'URL de l'agent dans la partie remote process.
III-D. Localisation du MBean▲
Une fois la connexion établie, dans l'onglet MBeans de JConsole, on trouve tous les MBeans enregistrés sur le serveur auquel on s'est connecté dans notre cas, on trouve HelloObject.
III-E. Accès aux attributs du MBean▲
Une fois le MBean localisé, on peut accéder à ses attributs et éventuellement les changer s'ils ne sont pas read-only, dans l'exemple démonstratif le MBean HelloObject a un attribut qui se nomme HelloWord qui a comme valeur « Bonjour ».
III-F. Invocation des opérations du MBean▲
On peut également appeler les opérations fournies par un MBean, dans l'exemple démonstratif, on appelle la méthode add avec comme paramètres 5 et 6, elle retourne la valeur 11.
IV. Sécurisation de l'accès aux MBeans▲
Afin de restreindre l'accès aux MBeans, Sun a mis à disposition des développeurs un mécanisme de contrôle d'accès aux MBeans avec un nom d'utilisateur et un mot de passe. Dans ce qui suit, nous donnerons un exemple démonstratif accompagné de quelques explications.
Remarque
La sécurisation de l'accès aux MBeans avec un mot de passe ne marche qu'en connexion distante, les utilisateurs locaux pourront accéder aux MBeanx sans aucune restriction.
IV-A. Création des variables d'environnement▲
import
java.lang.management.ManagementFactory;
import
java.rmi.registry.LocateRegistry;
import
java.util.HashMap;
import
java.util.Map;
import
javax.management.MBeanServer;
import
javax.management.remote.JMXConnectorServer;
import
javax.management.remote.JMXConnectorServerFactory;
import
javax.management.remote.JMXServiceURL;
public
class
MainSecurity {
public
static
void
main
(
String[] args) throws
Exception {
MBeanServer mbs =
ManagementFactory.getPlatformMBeanServer
(
);
LocateRegistry.createRegistry
(
9999
);
Map env =
new
HashMap
(
);
env.put
(
"jmx.remote.x.password.file"
, "jmx.password"
); // ligne 1
env.put
(
"jmx.remote.x.access.file"
, "jmx.access"
); // ligne 2
JMXServiceURL url =
new
JMXServiceURL
(
"service:jmx:rmi://localhost/jndi/rmi://localhost:9999/server"
);
JMXConnectorServer cs =
JMXConnectorServerFactory
.newJMXConnectorServer
(
url, <
b>
env</
b>
, mbs);
cs.start
(
);
while
(
true
) {
Thread.sleep
(
1000
);
}
}
}
Dans l'exemple, on définit deux variables d'environnement : jmx.remote.x.password.file et jmx.remote.x.access.file, ces deux variables doivent avoir respectivement comme valeur le fichier qui contient le nom d'utilisateur et le mot de passe de chaque utilisateur et le fichier qui contient les droits d'accès de chaque utilisateur. La structure de chacun de ces fichiers va être discutée dans ce qui suit.
IV-B. Le fichier jmx.password▲
selim mouna
sdfsdf 123456
Le format d'une entrée de ce fichier est très simple, il est défini comme suit :
<username> <password>
où username et password sont respectivement le nom d'utilisateur et le mot de passe d'un utilisateur. Dans notre fichier, on a deux utilisateurs, "selim" et "sdfsdf", qui ont respectivement pour mot de passe "mouna" et "123456".
IV-C. le fichier jmx.access▲
sdfsdf readonly
selim readwrite
Le format d'une entrée de ce fichier est très simple, il est défini comme suit :
<username> <droits>
où username et droits sont respectivement le nom d'utilisateur et le droit d'accès d'un utilisateur. Dans notre cas, l'utilisateur sdfsdf a le droit de lire, mais n'a pas le droit de modifier les attributs des MBeans contrairement à "selim" qui peut lire et modifier les attributs des MBeans.
V. Utilisation de HTML Adaptor▲
HTML Adaptor est fourni par Sun microsystems avec l'implémentation de référence de JMX (il n'est pas fourni avec J2SE 5.0). HTML Adaptor vous donne la possibilité d'administrer des MBeans en utilisant un navigateur web. Il permet d'interagir avec l'agent afin de voir les MBeans enregistrés et leurs attributs. En d'autres termes, HTML Adaptor est un outil simple et puissant qui vous permet de :
- voir les valeurs des attributs des MBeans s'ils sont readable ;
- changer les valeurs des attributs des MBeans s'ils sont writable ;
- invoquer des méthodes.
Le code suivant illustre un Agent JMX qui utilise HTML Adaptor.
package
org.sdf;
import
java.lang.management.ManagementFactory;
import
javax.management.MBeanServer;
import
javax.management.ObjectName;
import
com.sun.jdmk.comm.HtmlAdaptorServer;
public
class
MainAdaptor {
/**
*
@param
args
*/
public
static
void
main
(
String[] args) {
try
{
MBeanServer mbs =
ManagementFactory.getPlatformMBeanServer
(
);
ObjectName name =
new
ObjectName
(
"Hello:type=HelloObject"
);
Hello h =
new
Hello
(
);
h.setHelloWord
(
"Bonjour"
);
mbs.registerMBean
(
h, name);
HtmlAdaptorServer adapter =
new
HtmlAdaptorServer
(
);
adapter.setPort
(
8000
);
mbs.registerMBean
(
adapter, new
ObjectName
(
"AgentAdaptor:name=htmladapter,port=8000"
));
adapter.start
(
);
while
(
true
) {
System.out.println
(
h.getHelloWord
(
));
Thread.sleep
(
3000
);
}
}
catch
(
Exception e) {
}
}
}
Pour essayer HTML Adaptor avec cette application, il vous faudra :
- Télécharger l'implémentation de référence de JMX. Ceci est nécessaire parce que MainAdaptor utilise la classe HTMLAdaptor, qui se trouve dans l'implémentation de référence de JMX, vous avez seulement besoin du fichier jmxtools.jar ;
- Compiler tous les fichiers .java. Vérifier que jmxtools.jar est dans votre classpath ;
- Exécuter MainAdaptor. Cette application va être exécutée en tant que serveur ;
- Se connecter à l'agent JMX en entrant l'URL http://localhost:8000 dans votre navigateur web.
V-A. Agent view▲
Cette page fournit la liste des MBeans contenus dans cet agent. Vous pouvez filtrer cette liste pour avoir une vue plus raffinée.
V-B. MBean view▲
Cette page fournit des détails à propos d'un MBean spécifique. Ici vous pouvez lire et modifier les attributs et invoquer les méthodes des MBeans.
VI. Spring JMX▲
VI-A. Introduction▲
Le support de JMX dans Spring offre des fonctionnalités simples et transparentes pour intégrer votre application Spring dans une infrastructure JMX. Spring JMX vous permet :
- d'enregistrer automatiquement n'importe quel bean Spring en tant que MBean JMX ;
- de contrôler l'interface d'administration de vos beans avec un mécanisme flexible ;
- d'exposer vos MBeans d'une manière déclarative avec les connecteurs JSR-160 ;
- …
Ces fonctionnalités sont conçues de façon à travailler sur vos composants Spring et JMX indépendamment, dans la plupart des cas, votre application n'a pas besoin d'être au courant de Spring ou JMX pour bénéficier des avantages de Spring JMX.
VI-B. Enregistrement des beans dans un MBeanServer▲
La classe principale de Spring JMX est MBeanExporter. Cette classe est responsable de prendre en charge et d'enregistrer vos beans Spring dans un MBeanServer. Par exemple, on considère la classe suivante :
package
org.sdf;
public
class
HelloBean implements
IHelloBean {
private
String helloWord;
public
int
add
(
int
x, int
y) {
return
x +
y;
}
public
String getHelloWord
(
) {
return
helloWord;
}
public
void
sayHello
(
) {
System.out.println
(
helloWord);
}
public
void
setHelloWord
(
String value) {
helloWord =
value;
}
}
Pour exposer les propriétés et les méthodes de ce bean en tant qu'attributs et opérations d'un MBean, vous devez simplement configurer une instance de la classe MBeanExporter dans votre fichier de configuration comme suit :
<beans>
<bean
id
=
"exporter"
class
=
"org.springframework.jmx.export.MBeanExporter"
lazy-init
=
"false"
>
<property
name
=
"beans"
>
<map>
<entry
key
=
"bean:name=testBean1"
value-ref
=
"testBean"
/>
</map>
</property>
</bean>
<bean
id
=
"testBean"
class
=
"org.sdf.HelloBean"
>
<property
name
=
"name"
value
=
"TEST"
/>
<property
name
=
"age"
value
=
"100"
/>
</bean>
</beans>
La définition pertinente de bean du fichier de configuration précédent est le bean exporté. Sa propriété « beans » permet de savoir exactement quels beans doivent être exportés aux MBeanServer. En général la clé de chaque entrée dans la Map beans est utilisée comme ObjectName pour le bean correspondant à la valeur de l'entrée. Avec cette configuration, le bean testBean est exposé en tant que MBean sous le nom bean:name=testBean1.
VI-C. Création d'un MBeanServer▲
Dans la configuration précédente, on a supposé que l'application est exécutée dans un environnement qui a un MBeanServer en cours d'exécution. Dans ce cas, Spring va essayer de localiser le MBeanServer en cours d'exécution et enregistrer vos beans dans ce serveur. Cette fonctionnalité est très utile quand votre application est exécutée dans un conteneur comme Tomcat ou Jetty qui a son propre MBeanServer. Toutefois, cette approche n'est pas utilisée si votre application est de type standalone, ou si elle est exécutée dans un conteneur qui n'offre pas un MBeanServer. Pour contourner ce problème, vous pouvez créer une instance de MBeanServer de façon déclarative, en ajoutant une instance de la classe org.springframework.jmx.support.MBeanServerFactoryBean dans votre configuration. Vous pouvez aussi vous assurer que le MBeanServer que vous avez créé sera utilisé en positionnant la propriété server de l'instance de MBeanExporter à la valeur retournée par MBeanServerFactoryBean.
Exemple :
<beans>
<bean
id
=
"mbeanServer"
class
=
"org.springframework.jmx.support.MBeanServerFactoryBean"
/>
<bean
id
=
"exporter"
class
=
"org.springframework.jmx.export.MBeanExporter"
>
<property
name
=
"beans"
>
<map>
<entry
key
=
"bean:name=testBean1"
value-ref
=
"testBean"
/>
</map>
</property>
<property
name
=
"server"
ref
=
"mbeanServer"
/>
</bean>
<bean
id
=
"testBean"
class
=
"org.sdf.HelloBean"
>
<property
name
=
"name"
value
=
"TEST"
/>
<property
name
=
"age"
value
=
"100"
/>
</bean>
</beans>
VI-D. Création d'un connecteur serveur▲
Spring JMX offre la possibilité de créer un connecteur serveur pour permettre l'accès au MBeanServer à distance. Pour cela il utilise le connecteur JSR-160.
Exemple :
<bean
id
=
"serverConnector"
class
=
"org.springframework.jmx.support.ConnectorServerFactoryBean"
>
<property
name
=
"objectName"
value
=
"connector:name=rmi"
/>
<property
name
=
"serviceUrl"
value
=
"service:jmx:rmi://localhost/jndi/rmi://localhost:9999/server"
/>
</bean>
VI-E. Sécurisation de l'accès au MBeanServer▲
Comme vu précédemment pour la sécurisation des MBeans, Spring JMX offre un mécanisme de sécurité semblable à celui vu précédemment. Pour cela il suffit de définir la propriété environnement du connecteur.
Exemple :
<bean
id
=
"serverConnector"
class
=
"org.springframework.jmx.support.ConnectorServerFactoryBean"
>
<property
name
=
"objectName"
value
=
"connector:name=rmi"
/>
<property
name
=
"serviceUrl"
value
=
"service:jmx:rmi://localhost/jndi/rmi://localhost:9999/server"
/>
<property
name
=
"environment"
>
<map>
<entry
key
=
"jmx.remote.x.password.file"
value
=
"jmx.password"
/>
<entry
key
=
"jmx.remote.x.access.file"
value
=
"jmx.access"
/>
</map>
</property>
</bean>
À noter que pour utiliser le connecteur RMI, une instance de RMIRegistry doit être lancée. Vous pouvez facilement lancer le registre RMI en utilisant ce bout de configuration :
<bean
id
=
"registry"
class
=
"org.springframework.remoting.rmi.RmiRegistryFactoryBean"
>
<property
name
=
"port"
value
=
"9999"
/>
</bean>
VII. Les MXBeans▲
VII-A. Introduction▲
La chose la plus importante qu'apportent les MXBeans est que n'importe quel client JMX sera capable de les gérer. Les MXBeans offrent un moyen convenable de rassembler des attributs, sans que le client soit configuré pour gérer cet ensemble. Les MXBeans se déclaraient de la même façon que les MBeans classiques, c'est-à-dire le nom de l'interface suffixé avec "MXBeans", mais contrairement aux MBeans classiques, pour une interface quelconque nommée "XYZMXBean", il n'est plus obligatoire de nommer la classe "XYZ", chaque méthode dans l'interface va définir un attribut ou une opération du MXBean. L'annotation @MXBean peut aussi être utilisée pour annoter l'interface Java, au lieu de suffixer le nom de cette interface avec MXBean.
VII-B. Problème avec les MBeans▲
Dans la conception d'une application, un développeur pourrait être contraint de rassembler quelques attributs dans une même classe, pour faciliter la lecture ou pour des soucis de design.
Exemple :
package
org.sdf;
public
class
User {
private
String nom;
private
String prenom;
private
int
numero;
private
String rue;
private
String ville;
public
int
getNumero
(
) {
return
numero;
}
public
void
setNumero
(
int
numero) {
this
.numero =
numero;
}
public
String getRue
(
) {
return
rue;
}
public
void
setRue
(
String rue) {
this
.rue =
rue;
}
public
String getVille
(
) {
return
ville;
}
public
void
setVille
(
String ville) {
this
.ville =
ville;
}
public
void
setNom
(
String nom) {
this
.nom =
nom;
}
public
void
setPrenom
(
String prenom) {
this
.prenom =
prenom;
}
public
String getNom
(
) {
return
nom;
}
public
String getPrenom
(
) {
return
prenom;
}
}
Le développeur de cette classe pourrait rassembler les attributs numero, rue et ville dans une seule et même classe.
Ceci donnera :
package
org.sdf;
public
class
Adresse {
private
int
numero;
private
String rue;
private
String ville;
public
Adresse
(
int
numero, String rue, String ville) {
super
(
);
this
.numero =
numero;
this
.rue =
rue;
this
.ville =
ville;
}
public
int
getNumero
(
) {
return
numero;
}
public
void
setNumero
(
int
numero) {
this
.numero =
numero;
}
public
String getRue
(
) {
return
rue;
}
public
void
setRue
(
String rue) {
this
.rue =
rue;
}
public
String getVille
(
) {
return
ville;
}
public
void
setVille
(
String ville) {
this
.ville =
ville;
}
}
Et la classe User sera simplement comme suit :
package
org.sdf;
public
class
User {
private
String nom;
private
String prenom;
private
Adresse adresse;
public
Adresse getAdresse
(
) {
return
adresse;
}
public
String getNom
(
) {
return
nom;
}
public
String getPrenom
(
) {
return
prenom;
}
public
void
setAdresse
(
Adresse adresse) {
this
.adresse =
adresse;
}
public
void
setNom
(
String nom) {
this
.nom =
nom;
}
public
void
setPrenom
(
String prenom) {
this
.prenom =
prenom;
}
}
Maintenant, supposons que le développeur veut faire un MBean de la classe User, il n'aura qu'à implémenter une interface nommé UserMBean définie comme suit :
package
org.sdf;
public
interface
UserMBean {
public
String getNom
(
);
public
void
setNom
(
String nom);
public
String getPrenom
(
);
public
void
setPrenom
(
String prenom);
public
Adresse getAdresse
(
);
public
void
setAdresse
(
Adresse adresse);
}
Lorsque le développeur enregistrera un MBean de la classe user dans un MBeanServer, un problème va survenir lors de l'accès à ce MBean avec un client JMX tel que JConsole.
Comme illustré dans la capture d'écran, JConsole sera incapable de récupérer la valeur de l'adresse, il va la marquer Unavailable.
VII-C. Comment éviter ce problème avec les MXBeans▲
La déclaration d'un MXBean est très similaire à celle d'un MBean. L'interface UserMBean de l'exemple précédent sera définie comme un MXBean comme suit :
package
org.sdf;
public
interface
UserMXBean {
public
String getNom
(
);
public
void
setNom
(
String nom);
public
String getPrenom
(
);
public
void
setPrenom
(
String prenom);
public
Adresse getAdresse
(
);
public
void
setAdresse
(
Adresse adresse);
}
Pour permettre aux clients JMX de gérer la valeur de l'attribut Adresse, on doit ajouter l'annotation @ConstructorProperties({"numero", "rue", "ville"}) devant le constructeur de la classe Adresse, comme suit :
package
org.sdf;
import
java.beans.ConstructorProperties;
public
class
Adresse {
private
int
numero;
private
String rue;
private
String ville;
@ConstructorProperties
(
{
"numero"
, "rue"
, "ville"
}
)
public
Adresse
(
int
numero, String rue, String ville) {
super
(
);
this
.numero =
numero;
this
.rue =
rue;
this
.ville =
ville;
}
public
int
getNumero
(
) {
return
numero;
}
public
void
setNumero
(
int
numero) {
this
.numero =
numero;
}
public
String getRue
(
) {
return
rue;
}
public
void
setRue
(
String rue) {
this
.rue =
rue;
}
public
String getVille
(
) {
return
ville;
}
public
void
setVille
(
String ville) {
this
.ville =
ville;
}
}
Cette annotation permet de faire savoir au client JMX que tel paramètre du constructeur est associé à tel attribut. Lorsqu'un client JMX accède à ce MXBean, il pourra gérer la valeur de l'attribut adresse.
VIII. Téléchargements des sources▲
IX. Conclusion▲
Le modèle de programmation JMX est à la fois simple et puissant, il peut refléter le comportement des différentes ressources matérielles ou logicielles en utilisant les conventions de la technologie JavaBeans.