C'est un titre comme "J'ai essayé de danser", mais c'est un article sérieux.
Il y a quelque temps, j'ai fait des recherches sur JMX dans un projet auquel j'ai participé, et j'ai pensé que si j'utilisais cela, je n'aurais pas à créer un écran de configuration pour des paramètres simples. Je pense qu'il est difficile de le recommander aux clients, mais j'ai pensé qu'il serait possible de réduire le nombre d'étapes nécessaires pour créer un écran de configuration pour les produits internes, j'ai donc créé une application capable de gérer facilement les informations de connexion et j'ai examiné la convivialité.
Cette fois, c'est une fonction simple, donc je n'utilise pas DB. J'ai utilisé Spring pour créer une application Web simple qui se connecte simplement. Les bibliothèques utilisées sont les suivantes.
Je décrirai brièvement les spécifications de la gestion des connexions.
Cela suffit pour la fonction de gestion des connexions. C'est ennuyeux d'implémenter trop de fonctionnalités.
J'ai créé une application Web simple qui se connecte simplement. L'implémentation est une application Web très courante utilisant Spring MVC. Il est implémenté pour que les informations de connexion puissent être visualisées sur JMX.
J'ai créé un MBean pour gérer les informations de connexion. Commencez par créer une interface.
public interface LoginMonitorMBean {
public static final String NAME = "examples.jmx:type=LoginMonitoring";
public static final String LUI_ITEM_ID = "id";
public static final String LUI_ITEM_NAME = "name";
public int getLoginCount();
public CompositeData[] getLoginInfos();
void addLoginInfo(CompositeData loginUserInfo);
public void removeLoginInfo(int id);
public void resetLoginInfo();
public int getMaxLoginCount();
public void setMaxLoginCount(int count);
public int[] getLoginLockIds();
public void addLoginLockId(int id);
public void removeLoginLockId(int id);
public void resetLoginLockId();
public static ObjectName createObjectName() {
try {
return new ObjectName(LoginMonitorMBean.NAME);
} catch (MalformedObjectNameException e) {
throw new IllegalArgumentException(e);
}
}
}
Il semble que MBean doit être ajouté à la fin du nom de l'interface. Ignorez les constantes et les méthodes statiques. C'est un groupe de méthodes que d'autres méthodes peuvent être utilisées à partir de jconsole. Une description de chaque méthode est donnée ci-dessous.
Nom de la méthode | Explication |
---|---|
getLoginCount | Vous pouvez obtenir le nombre de connexions. |
getLoginInfos | Vous pouvez obtenir l'ID et le nom de l'utilisateur connecté. |
addLoginInfo | Vous pouvez ajouter des informations de connexion. |
removeLoginInfo | Supprimez les informations de connexion de l'ID spécifié. |
resetLoginInfo | Réinitialisez vos informations de connexion. |
getMaxLoginCount | Vous pouvez obtenir le nombre maximum de connexions. |
setMaxLoginCount | Vous pouvez définir le nombre maximum de connexions. |
getLoginLockIds | Vous pouvez obtenir un tableau d'identifiants verrouillés. |
addLoginLockId | Vous pouvez ajouter un identifiant pour verrouiller. |
removeLoginLockId | Supprimez l'ID verrouillé. |
resetLoginLockId | Réinitialisez l'ID verrouillé. |
Créez une classe qui implémente l'interface créée précédemment.
public class LoginMonitor implements LoginMonitorMBean {
}
Une erreur se produit sauf si la classe de gestion est un nom de classe qui exclut les MBeans du nom de l'interface. Les détails d'implémentation sont omis, mais il s'agit essentiellement d'une implémentation simple qui contient et obtient les informations de connexion, l'ID de verrouillage, etc. dans le champ de classe.
Enregistrez le MBean contenant les informations de connexion. L'enregistrement est effectué au démarrage de l'application Web.
public class StartupBean {
private static Logger log = LoggerFactory.getLogger(StartupBean.class);
@PostConstruct
public void initAfterStartup() {
try {
log.info("Processus d'enregistrement MBean");
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbs.registerMBean(new LoginMonitor(), LoginMonitorMBean.createObjectName());
} catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
throw new IllegalStateException(e);
}
}
}
Le contenu des données ne peut pas être visualisé à partir de jconsole dans les classes de données (classes de type DTO) qui implémentent le setter / getter général.
Utilisez javax.management.openmbean.CompositeData
pour le rendre visible depuis jconsole etc.
Regardons un exemple de conservation des informations de connexion.
public class LoginUserInfo {
private static final String ID = LoginMonitorMBean.LUI_ITEM_ID;
private static final String NAME = LoginMonitorMBean.LUI_ITEM_NAME;
private final int id;
private final String name;
public LoginUserInfo(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void addMBean(LoginMonitorMBean mbean) throws OpenDataException {
CompositeType compositeType = new CompositeType(
"LoginUserInfo",
"Type de données contenant les informations de connexion de l'utilisateur",
new String[] { ID, NAME },
new String[] { "ID utilisateur de connexion", "Nom d'utilisateur connexion" },
new OpenType[] { SimpleType.INTEGER, SimpleType.STRING });
Map<String, Object> dataMap = new HashMap<>();
dataMap.put(ID, id);
dataMap.put(NAME, name);
mbean.addLoginInfo(new CompositeDataSupport(compositeType, dataMap));
}
public static int getMBeanId(CompositeData data) {
return (Integer) data.get(ID);
}
}
Voici un exemple où la méthode addMBean
enregistre les données de javax.management.openmbean.CompositeData
.
Ce LoginUserInfo
est une classe de données simple juste pour contenir les identifiants de connexion communs et les noms d'utilisateur de connexion.
L'ID utilisé lors de la connexion et le nom d'utilisateur obtenu à partir de la base de données etc. (valeur fixe car il s'agit d'une application simple) sont conservés.
Les informations de cette classe sont converties en javax.management.openmbean.CompositeDataSupport
, qui est une classe d'implémentation de l'interface javax.management.openmbean.CompositeData
.
En faisant cela, vous pouvez naviguer à partir de jconsole comme suit.
La fonction de connexion est simple. Après la connexion, le MBean géré par JMX est retiré, la limite de connexion et l'ID de verrouillage sont vérifiés, et s'il n'y a pas d'erreur, les informations de connexion sont enregistrées dans le MBean. Le «LoginController» implémenté est le suivant.
@Controller
public class LoginController {
@PostMapping("/login")
public String login(@Validated @ModelAttribute LoginForm form, BindingResult result, Model model) {
//Vérification des erreurs d'entrée
if (result.hasErrors()) {
model.addAttribute("validationError", "Erreur d'entrée");
return "login";
}
//Vérification de connexion
if (100 > form.getLoginId() && 300 < form.getLoginId()) {
model.addAttribute("validationError", "Erreur d'identification");
return "login";
}
if (!"testtest".equals(form.getLoginPasswd())) {
model.addAttribute("validationError", "Erreur d'identification");
return "login";
}
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
LoginMonitorMBean mbean = JMX.newMBeanProxy(mbs, LoginMonitorMBean.createObjectName(), LoginMonitorMBean.class);
//Vérifiez le nombre de connexions
if (mbean.getMaxLoginCount() > 0 && mbean.getLoginCount() >= mbean.getMaxLoginCount()) {
model.addAttribute("validationError", "Limite du nombre de connexion");
return "login";
}
//Vérification du verrouillage d'identité
if (Arrays.stream(mbean.getLoginLockIds()).filter(lockId -> lockId == form.getLoginId()).findFirst()
.isPresent()) {
model.addAttribute("validationError", "ID verrouillé");
return "login";
}
//Enregistrement des informations de connexion
try {
LoginUserInfo info = new LoginUserInfo(form.getLoginId(),
String.format("Utilisateur test (%d)", form.getLoginId()));
info.addMBean(mbean);
} catch (OpenDataException e) {
e.printStackTrace();
model.addAttribute("validationError", "Erreur système interne");
return "login";
}
model.addAttribute("loginCount", mbean.getLoginCount());
return "home";
}
}
Étant donné que cette application Web est Spring Boot, elle peut être démarrée comme suit.
java -jar jmx-examples-1.0.0.war
Afin de vérifier à distance le MBean enregistré, il est nécessaire de définir les paramètres de démarrage comme suit.
java -Dcom.sun.management.jmxremote.port=5000 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -jar jmx-examples-1.0.0.war
Paramètres de démarrage | Explication |
---|---|
com.sun.management.jmxremote.port | Vous pouvez spécifier le numéro de port du serveur MBean. |
com.sun.management.jmxremote.authenticate | Cette fois, comme il s'agit d'une fonction simple, la fonction d'authentification lors de l'accès au serveur MBean est désactivée. |
com.sun.management.jmxremote.ssl | Cette fois, par souci de simplicité, SSL est désactivé lors de l'accès au serveur MBean. |
Si vous le démarrez comme ci-dessus, vous pouvez y accéder par un processus distant depuis jconsole etc.
Il est accessible depuis les processus locaux et distants depuis jconsole, mais j'ai essayé de créer une application cliente qui accède à distance avec l'ID de processus de la même manière.
Reportez-vous à la page suivante pour savoir comment connecter JMX. 2 Monitoring and Management Using JMX Technology
Pour accéder à distance au serveur MBean, vous devez spécifier les paramètres de démarrage de com.sun.management.jmxremote.port
.
L'adresse suivante est générée à l'aide du numéro de port spécifié dans le paramètre de démarrage ci-dessus.
service:jmx:rmi:///jndi/rmi://localhost:5000/jmxrmi
Utilisez ensuite l'adresse ci-dessus pour vous connecter au serveur MBean.
String connectAddress = "service:jmx:rmi:///jndi/rmi://localhost:5000/jmxrmi";
try (JMXConnector jmxc = JMXConnectorFactory.connect(new JMXServiceURL(connectAddress))) {
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
LoginMonitorMBean lmbean = JMX.newMBeanProxy(mbsc, LoginMonitorMBean.createObjectName(),
LoginMonitorMBean.class);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Un ID de processus est requis pour l'accès local. Si vous connaissez l'ID de processus, vous pouvez vous connecter, vous n'avez donc pas besoin de spécifier les paramètres de démarrage.
String CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress";
VirtualMachine vm = VirtualMachine.attach(pid);
String connectorAddress;
try {
connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
if (connectorAddress == null) {
vm.startLocalManagementAgent();
connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
}
} finally {
vm.detach();
}
Puisque la chaîne de caractères pour la connexion peut être obtenue avec la logique ci-dessus, il est possible de se connecter au processus local avec la description suivante décrite même pour une connexion à distance utilisant cette chaîne de caractères.
JMXConnector jmxc = JMXConnectorFactory.connect(new JMXServiceURL(connectAddress))
En vous connectant au serveur MBean, vous pouvez obtenir les informations JVM en plus du MBean enregistré. Le MBean pour l'acquisition du nom de la machine virtuelle et de l'ID de processus et le MBean pour l'acquisition des informations de segment de mémoire peuvent être acquis avec la description suivante.
try (JMXConnector jmxc = JMXConnectorFactory.connect(new JMXServiceURL(connectAddress))) {
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
//Afficher les informations d'exécution pour les machines virtuelles Java
RuntimeMXBean rmxbean = ManagementFactory.getPlatformMXBean(mbsc, RuntimeMXBean.class);
//Obtenir l'ID de processus, etc. du bean rmx
//Afficher les informations de mémoire
MemoryMXBean mmxbean = ManagementFactory.getPlatformMXBean(mbsc, MemoryMXBean.class);
MemoryUsage memoryUsage = mmxbean.getHeapMemoryUsage();
//Obtenir des informations de tas de mémoire
//Afficher les informations du système d'exploitation
OperatingSystemMXBean omxbean = ManagementFactory.getPlatformMXBean(mbsc, OperatingSystemMXBean.class);
//Obtenir des informations sur le système d'exploitation d'omxbean
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Lorsque j'ai essayé d'utiliser JMX, c'était tellement simple et pratique que je n'avais pas besoin de créer un écran de réglage avec une seule zone de texte. Bien sûr, si vous rencontrez des problèmes de performances et des informations de configuration dans la base de données, vous pouvez vous demander si vous pouvez vous connecter à la base de données et combien la charge est, mais vous pouvez facilement modifier les paramètres avec jconsole, donc l'effort de créer l'écran J'ai senti qu'il pouvait être réduit. L'application créée cette fois-ci est stockée dans le référentiel suivant, alors jetez un œil.
Recommended Posts