Es ist ein Titel wie "Ich habe versucht zu tanzen", aber es ist ein ernsthafter Artikel.
Vor einiger Zeit habe ich JMX in einem Projekt recherchiert, an dem ich teilgenommen habe, und ich dachte, wenn ich dies verwenden würde, müsste ich keinen Einstellungsbildschirm für einfache Einstellungen erstellen. Ich denke, es ist schwierig, es Kunden zu empfehlen, aber ich dachte, dass es möglich sein würde, die Anzahl der Schritte zu reduzieren, die zum Erstellen eines Einstellungsbildschirms für interne Produkte erforderlich sind. Deshalb habe ich eine App erstellt, mit der Anmeldeinformationen einfach verwaltet und die Benutzerfreundlichkeit überprüft werden können.
Diesmal ist es eine einfache Funktion, daher verwende ich keine DB. Ich habe Spring verwendet, um eine einfache Webanwendung zu erstellen, die sich nur anmeldet. Die verwendeten Bibliotheken sind wie folgt.
Ich werde kurz die Spezifikationen der Login-Verwaltung beschreiben.
Dies reicht für die Login-Management-Funktion aus. Es ist ärgerlich, zu viele Funktionen zu implementieren.
Ich habe eine einfache Webanwendung erstellt, die sich nur anmeldet. Die Implementierung ist eine sehr verbreitete Webanwendung, die Spring MVC verwendet. Es ist so implementiert, dass die angemeldeten Informationen in JMX angezeigt werden können.
Ich habe eine MBean zum Verwalten von Anmeldeinformationen erstellt. Erstellen Sie zunächst eine Schnittstelle.
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);
}
}
}
Es scheint, dass MBean am Ende des Schnittstellennamens hinzugefügt werden muss. Ignorieren Sie Konstanten und statische Methoden. Es ist eine Gruppe von Methoden, mit denen andere Methoden von jconsole aus bedient werden können. Eine Beschreibung jeder Methode ist unten angegeben.
Methodenname | Erläuterung |
---|---|
getLoginCount | Sie können die Anzahl der Anmeldungen abrufen. |
getLoginInfos | Sie können die ID und den Namen des angemeldeten Benutzers abrufen. |
addLoginInfo | Sie können Anmeldeinformationen hinzufügen. |
removeLoginInfo | Löschen Sie die Anmeldeinformationen der angegebenen ID. |
resetLoginInfo | Setzen Sie Ihre Anmeldeinformationen zurück. |
getMaxLoginCount | Sie können die maximale Anzahl von Anmeldungen erhalten. |
setMaxLoginCount | Sie können die maximale Anzahl von Anmeldungen festlegen. |
getLoginLockIds | Sie können ein Array gesperrter IDs abrufen. |
addLoginLockId | Sie können eine zu sperrende ID hinzufügen. |
removeLoginLockId | Löschen Sie die gesperrte ID. |
resetLoginLockId | Setzen Sie die gesperrte ID zurück. |
Erstellen Sie eine Klasse, die die zuvor erstellte Schnittstelle implementiert.
public class LoginMonitor implements LoginMonitorMBean {
}
Ein Fehler tritt auf, es sei denn, die Verwaltungsklasse ist ein Klassenname, der MBeans vom Schnittstellennamen ausschließt. Die Implementierungsdetails werden weggelassen, aber im Grunde handelt es sich um eine einfache Implementierung, die Anmeldeinformationen, Sperren-ID usw. im Klassenfeld enthält und abruft.
Registrieren Sie die MBean, die die Anmeldeinformationen enthält. Die Registrierung erfolgt beim Start der Webanwendung.
public class StartupBean {
private static Logger log = LoggerFactory.getLogger(StartupBean.class);
@PostConstruct
public void initAfterStartup() {
try {
log.info("MBean Registrierungsprozess");
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbs.registerMBean(new LoginMonitor(), LoginMonitorMBean.createObjectName());
} catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
throw new IllegalStateException(e);
}
}
}
Dateninhalte können nicht von jconsole in einer Datenklasse (DTO-ähnliche Klasse) angezeigt werden, in der ein allgemeiner Setter / Getter implementiert ist.
Verwenden Sie javax.management.openmbean.CompositeData
, um es von jconsole usw. aus sichtbar zu machen.
Schauen wir uns ein Beispiel für das Beibehalten von Anmeldeinformationen an.
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",
"Datentyp, der Anmeldebenutzerinformationen enthält",
new String[] { ID, NAME },
new String[] { "Benutzer-ID anmelden", "Login Benutzername" },
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);
}
}
Dies ist ein Beispiel, in dem die Methode "addMBean" die Daten von "javax.management.openmbean.CompositeData" registriert.
Diese LoginUserInfo
ist eine einfache Datenklasse, die nur allgemeine Login-IDs und Login-Benutzernamen enthält.
Die bei der Anmeldung verwendete ID und der aus der Datenbank usw. erhaltene Benutzername (fester Wert, da dies eine einfache Anwendung ist) bleiben erhalten.
Die Informationen in dieser Klasse werden in "javax.management.openmbean.CompositeDataSupport" konvertiert, eine Implementierungsklasse der Schnittstelle "javax.management.openmbean.CompositeData".
Auf diese Weise können Sie wie folgt von jconsole aus navigieren.
Die Anmeldefunktion ist einfach. Nach dem Anmelden wird die von JMX verwaltete MBean entfernt, das Anmeldelimit und die Sperr-ID werden überprüft. Wenn kein Fehler auftritt, werden die Anmeldeinformationen in der MBean registriert. Der implementierte "LoginController" ist wie folgt.
@Controller
public class LoginController {
@PostMapping("/login")
public String login(@Validated @ModelAttribute LoginForm form, BindingResult result, Model model) {
//Eingabefehlerprüfung
if (result.hasErrors()) {
model.addAttribute("validationError", "Eingabe Fehler");
return "login";
}
//Anmeldeprüfung
if (100 > form.getLoginId() && 300 < form.getLoginId()) {
model.addAttribute("validationError", "Login Fehler");
return "login";
}
if (!"testtest".equals(form.getLoginPasswd())) {
model.addAttribute("validationError", "Login Fehler");
return "login";
}
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
LoginMonitorMBean mbean = JMX.newMBeanProxy(mbs, LoginMonitorMBean.createObjectName(), LoginMonitorMBean.class);
//Überprüfen Sie die Anzahl der Anmeldungen
if (mbean.getMaxLoginCount() > 0 && mbean.getLoginCount() >= mbean.getMaxLoginCount()) {
model.addAttribute("validationError", "Anmeldungsnummernlimit");
return "login";
}
//ID-Sperrprüfung
if (Arrays.stream(mbean.getLoginLockIds()).filter(lockId -> lockId == form.getLoginId()).findFirst()
.isPresent()) {
model.addAttribute("validationError", "ID gesperrt");
return "login";
}
//Registrierung der Anmeldeinformationen
try {
LoginUserInfo info = new LoginUserInfo(form.getLoginId(),
String.format("Benutzer testen (%d)", form.getLoginId()));
info.addMBean(mbean);
} catch (OpenDataException e) {
e.printStackTrace();
model.addAttribute("validationError", "Interner Systemfehler");
return "login";
}
model.addAttribute("loginCount", mbean.getLoginCount());
return "home";
}
}
Da es sich bei dieser Webanwendung um Spring Boot handelt, kann sie wie folgt gestartet werden.
java -jar jmx-examples-1.0.0.war
Um die registrierte MBean remote zu überprüfen, müssen die Startparameter wie folgt eingestellt werden.
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
Startparameter | Erläuterung |
---|---|
com.sun.management.jmxremote.port | Sie können die Portnummer des MBean-Servers angeben. |
com.sun.management.jmxremote.authenticate | Da es sich um eine einfache Funktion handelt, ist diesmal die Authentifizierungsfunktion beim Zugriff auf den MBean-Server deaktiviert. |
com.sun.management.jmxremote.ssl | Dieses Mal ist SSL der Einfachheit halber beim Zugriff auf den MBean-Server deaktiviert. |
Wenn Sie es wie oben starten, können Sie über einen Remote-Prozess von jconsole usw. darauf zugreifen.
Auf den Zugriff kann sowohl von lokalen als auch von Remote-Prozessen über jconsole aus zugegriffen werden. Ich habe jedoch versucht, eine Client-Anwendung zu erstellen, die auf dieselbe Weise auf die Prozess-ID zugreift.
Auf der folgenden Seite erfahren Sie, wie Sie JMX verbinden. 2 Monitoring and Management Using JMX Technology
Um remote auf den MBean-Server zugreifen zu können, müssen Sie die Startparameter für "com.sun.management.jmxremote.port" angeben. Generieren Sie die folgende Adresse mit der im obigen Startparameter angegebenen Portnummer.
service:jmx:rmi:///jndi/rmi://localhost:5000/jmxrmi
Verwenden Sie dann die oben angegebene Adresse, um eine Verbindung zum MBean-Server herzustellen.
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();
}
Für den lokalen Zugriff ist eine Prozess-ID erforderlich. Wenn Sie die Prozess-ID kennen, können Sie eine Verbindung herstellen, sodass Sie die Startparameter nicht angeben müssen.
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();
}
Da die Zeichenfolge für die Verbindung mit der obigen Logik erhalten werden kann, ist es möglich, eine Verbindung zum lokalen Prozess mit der folgenden Beschreibung herzustellen, die auch für die Fernverbindung unter Verwendung dieser Zeichenfolge beschrieben wird.
JMXConnector jmxc = JMXConnectorFactory.connect(new JMXServiceURL(connectAddress))
Durch Herstellen einer Verbindung zum MBean-Server können Sie die JVM-Informationen zusätzlich zur registrierten MBean abrufen. Die MBean zum Abrufen des Namens und der Prozess-ID der virtuellen Maschine und die MBean zum Abrufen von Heap-Informationen können mit der folgenden Beschreibung abgerufen werden.
try (JMXConnector jmxc = JMXConnectorFactory.connect(new JMXServiceURL(connectAddress))) {
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
//Laufzeitinformationen für virtuelle Java-Maschinen anzeigen
RuntimeMXBean rmxbean = ManagementFactory.getPlatformMXBean(mbsc, RuntimeMXBean.class);
//Prozess-ID usw. von rmx bean abrufen
//Speicherinformationen anzeigen
MemoryMXBean mmxbean = ManagementFactory.getPlatformMXBean(mbsc, MemoryMXBean.class);
MemoryUsage memoryUsage = mmxbean.getHeapMemoryUsage();
//Holen Sie sich Heap-Informationen von memoryUsage
//Betriebssysteminformationen anzeigen
OperatingSystemMXBean omxbean = ManagementFactory.getPlatformMXBean(mbsc, OperatingSystemMXBean.class);
//Holen Sie sich Betriebssysteminformationen von omxbean
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Als ich versuchte, JMX zu verwenden, war es so einfach und bequem, dass ich keinen Einstellungsbildschirm mit nur einem Textfeld erstellen musste. Wenn Sie Leistungsprobleme haben und Informationen in der Datenbank einstellen, können Sie natürlich überlegen, ob Sie eine Verbindung zur Datenbank herstellen können, wie hoch die Last ist usw. Ich hatte das Gefühl, dass es reduziert werden könnte. Die diesmal erstellte Anwendung wird im folgenden Repository gespeichert. Schauen Sie also bitte vorbei.
Recommended Posts