Administration des ressources avec JMX
Date de publication : 10 octobre 2008
Par
Selim KEBIR (Mon site) (Blog)
Cet article a été rédigé pour permettre d'étudier les différentes couches d'une application répondant aux spécifications JMX. Les principales fonctionnalités des clients JMX sont discutées et accompagnées de plusieurs exemples illustratifs.
I. Introduction
I-A. JMX
I-B. les MBeans
I-C. Activer/Désactiver le MBeanServer
I-C-1. Activer l'agent JMX
I-C-2. Désactiver l'agent JMX
I-D. L'API pour interroger le MBeanServer
I-E. JConsole
I-F. Survol des MBean présents par défaut
I-F-1. Gestion de la mémoire
I-F-2. Gestion des threads
I-F-3. Gestion des niveaux logs
II. Exemple de connexion à un agent JMX
II-A. Création d'un connecteur RMI
II-B. Utilisation d'un proxy pour travailler sur un MBean distant
II-B-1. Sous J2SE 5.0
II-B-2. Sous J2SE 6.0
II-C. Utilisation d'un filtre pour récupérer plusieurs MBeans d'un agent JMX
II-C-1. Exemple
III. Exemple d'administration d'un MBean avec JConsole
III-A. Boite de dialogue de connexion
III-B. Création du MBean et de l'agent JMX
III-B-1. Le MBean
III-B-2. L'agent JMX
III-C. Connexion à l'agent
III-D. Localisation du MBean
III-E. Accès aux attributs du MBean
III-F. Invocation des opérations du MBean
IV. Sécurisation de l'accès aux MBeans
IV-A. Création des variables d'environnement
IV-B. Le fichier jmx.password
IV-C. le fichier jmx.access
V. Utilisation de HTML Adaptor
V-A. Agent view
V-B. MBean view
VI. Spring JMX
VI-A. Introduction
VI-B. Enregistrement des beans dans un MBeanServer
VI-C. Création d'un MBeanServer
VI-D. Création d'un connecteur serveur
VI-E. Sécurisation de l'accès au MBeanServer
VII. Les MXBeans
VII-A. Introduction
VII-B. Problème avec les MBeans
VII-C. Comment éviter ce problème avec les MXBeans
VIII. Téléchargements de sources
IX. Conclusion
X. Remerciements
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 APIs, et des services pour construire des solutions distribuées, dynamiques, et modulaires pour la gestion de ressources de tout types, 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 application 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'outil 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éfini 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();
public void setAttrName(AttrType val);
|
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 et 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 colonne (:). Si le domaine inclue 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.
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 operations.
Il existe 6 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 specifiés.
- Les méthodes setAttribute et setAttributes() modifient les valeurs des attributs du MBean specifiés.
- La méthode invoke() exécute une opération sur le MBean specifié.
- L'objet de type MBeanInfo retourné par la méthode getMBeanInfo() encapsule des méta donné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 suivie 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 lancez 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 taches 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ée 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 local.
Le connecteur client crée 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ée 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éthode 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éfinit 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 fournit 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)
attr(String name)
eq(ValueExp v1, ValueExp v2)
value(String val)
|
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 fournit 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 3 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:
| HelloMBean.java |
package org.sdf;
public interface HelloMBean {
public void sayHello();
public int add(int x, int y);
public String getHelloWord();
public void setHelloWord(String value);
}
|
| Hello.java |
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.
| Main.java |
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
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
| MainSecurity.java |
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");
env.put("jmx.remote.x.access.file", "jmx.access");
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
| 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 :
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
| jmx.access |
sdfsdf readonly
selim readwrite
|
Le format d'une entrée de ce fichier est très simple, il est définit comme suit :
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.
| MainAdaptor.java |
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
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é 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ée 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'apporte 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 ensemble, 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 probleme 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 :
| UserMXBean.java |
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 :
| Adresse.java |
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 de 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.
X. Remerciements
Tout d'abord, je tiens à remercier
RideKick et
acacia d'avoir pris la peine de relire et corriger cet article.
Je remercie également
Ricky81 et
hikage pour leurs précieux commentaires. Car sans eux, cet article n'aurait pas vu le jour.

