[JAVA] Ich habe versucht, Anmeldeinformationen mit JMX zu verwalten

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.

Umgebung

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.

Anmeldeverwaltungsspezifikationen

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.

Informationen zur serverseitigen Implementierung

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.

Erstellen einer MBean-Schnittstelle

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 einer Verwaltungsklasse

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.

MBean Registrierung

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);
        }
    }

}

Informationen zu der Klasse, die Anmeldeinformationen enthält

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.

image.png

Informationen zur Anmeldefunktion

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";
    }

}

Startparameter

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.

Informationen zur clientseitigen Implementierung

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

Fernzugriff

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();
}

Lokaler Zugang

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))

JVM-Informationen

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();
}

Zusammenfassung

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.

jmx-examples

Recommended Posts

Ich habe versucht, Anmeldeinformationen mit JMX zu verwalten
Ich habe versucht, die Federbeinkonfiguration mit Coggle zu verwalten
Ich habe versucht, mit Java zu interagieren
Ich habe versucht, mit Web Assembly zu beginnen
Ich habe versucht, AdoptOpenJDK 11 (11.0.2) mit dem Docker-Image zu überprüfen
Ich habe versucht, eine Standardauthentifizierung mit Java durchzuführen
Ich habe versucht, den Block mit Java zu brechen (1)
Ich habe versucht, was ich mit Stream leise versuchen wollte.
Ich habe versucht, das Hochladen von Dateien mit Spring MVC zu implementieren
Ich habe versucht, CSV mit Outsystems zu lesen und auszugeben
Ich habe versucht, TCP / IP + BIO mit JAVA zu implementieren
[Java 11] Ich habe versucht, Java auszuführen, ohne mit Javac zu kompilieren
Ich habe MySQL 5.7 mit Docker-Compose gestartet und versucht, eine Verbindung herzustellen
Ich habe versucht, mit Spring Data JPA zu beginnen
Ich habe versucht, eine Anmeldefunktion mit Java zu erstellen
Ich habe versucht, Animationen mit der Blazor + Canvas-API zu zeichnen
Ich habe versucht, Sterling Sort mit Java Collector zu implementieren
Ich habe UPSERT mit PostgreSQL ausprobiert.
Ich habe BIND mit Docker ausprobiert
Ich habe versucht, yum-cron zu verifizieren
Ich habe versucht, mit Chocolatey eine Java8-Entwicklungsumgebung zu erstellen
Ich habe versucht, eine Java EE-Anwendung mit OpenShift zu modernisieren.
Ich habe versucht, die Verarbeitungsgeschwindigkeit mit spiritueller Technik zu erhöhen
[Rails] Ich habe versucht, eine Mini-App mit FullCalendar zu erstellen
Ich habe versucht, den Chat mit dem Minecraft-Server mit der Discord-API zu verknüpfen
[Rails] Ich habe versucht, die Stapelverarbeitung mit der Rake-Task zu implementieren
Ich habe versucht, mit Docker eine Padrino-Entwicklungsumgebung zu erstellen
Ich habe versucht, mit Swagger mit Spring Boot zu beginnen
Ich habe versucht, mit Ractor mehrere Objekte übergeben zu können
Ich habe versucht, C # (Indexer) zu kauen.
Ich habe versucht, JOOQ mit Gradle zu verwenden
Ich habe eine morphologische Analyse mit MeCab versucht
Ich habe versucht, die Unterstützung für iOS 14 zusammenzufassen
Ich habe versucht, UDP mit Java zu kommunizieren
Ich habe versucht, die Methode zu erklären
Ich habe GraphQL mit Spring Boot ausprobiert
Ich habe versucht, das Java-Lernen zusammenzufassen (1)
Ich habe Flyway mit Spring Boot ausprobiert
Ich habe jetzt versucht, Java 8 zusammenzufassen
C # (Polymorphismus: Polymorphismus)
Ich habe versucht, Slim mit Scaffold anzupassen
Ich habe versucht, Active Hash zu erklären
Ich habe versucht, das Problem der "mehrstufigen Auswahl" mit Ruby zu lösen
Ich habe versucht, mit Docker eine Plant UML Server-Umgebung zu erstellen
Ich habe versucht, mithilfe von JDBC Template mit Spring MVC eine Verbindung zu MySQL herzustellen
Ich habe versucht, die Bildvorschau mit Rails / jQuery zu implementieren
Ich habe versucht, mit Eclipse + Tomcat eine http2-Entwicklungsumgebung zu erstellen
Ich habe versucht, eine flexible ODER-Zuordnung mit MyBatis Dynamic SQL zu implementieren
Ich habe versucht, Ruby's Float (arg, Ausnahme: true) mit Builtin neu zu implementieren
Ich habe versucht, eine Android-Anwendung mit MVC zu erstellen (Java)
Ich habe versucht, den Betrieb des gRPC-Servers mit grpcurl zu überprüfen