Как программно сделать вызов метода через JMX.

java jmx

В этой статье я не буду рассказывать как создать MBean, чтобы вызывать его методы через JMX. Это больше заметка для себя и других, кому может понадобиться из приложения вызвать метод удалённо в другом Java-приложении.

Мой случай:

на продакшине (в закрытой сети, без возможности установить какой либо софт дополнительно) необходимо вызвать операцию через jconsole, всё ничего, да вот нужная операция принимает аргументы в виде String…(varargs), а jconsole не умеет так вызывать методы, ей подавай только простые аргументы. Да ситуация решается более продвинутые инструменты типа JProfiler и другими, но их нет на данном сервере и никто не даст их туда поставить или открыть порты наружу, чтоб удалённо это сделать. Вот так за 30минут с гуглом, получился вот такой app.

import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

public class Main {

    public static void main(String[] args) throws IOException {
        //Хост "localhost"
        final String hostName = args[0];

        //порт "1099"
        final String portNum = args[1];

        //Аргумент для вызываемой
        final String[] argsForOperations = args[2].split(",");

        //Наименование bean-а
        final String BEAN_NAME = "bean:name=exampleMXBean";

        //Вызываемая операция
        final String OPERATION_FOR_RUN = "launchRocketToMars";

        JMXConnector connector = null;
        try {
            JMXServiceURL u = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + hostName + ":" + portNum +  "/jmxrmi");
            connector = JMXConnectorFactory.connect(u);
            MBeanServerConnection remote = connector.getMBeanServerConnection();

            ObjectName bean = new ObjectName(BEAN_NAME);

            MBeanInfo info = remote.getMBeanInfo(bean);
            final MBeanOperationInfo[] operations = info.getOperations();

            final MBeanOperationInfo mBeanOperationInfo = Arrays.stream(operations)
                    .filter(it -> it.getName().equals(OPERATION_FOR_RUN))
                    .findFirst()
                    .orElse(null);

            if (Objects.isNull(mBeanOperationInfo)) {
                System.out.println("Operation " + OPERATION_FOR_RUN + " not found!");
                return;
            }

            String  operationSignature[] = {String[].class.getName()};

            //Вызов операции
            remote.invoke(bean, OPERATION_FOR_RUN, new Object[] {argsForOperations}, operationSignature);
            System.out.println("Operation " + OPERATION_FOR_RUN + " invoked! With arguments: " + args[2]);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (Objects.nonNull(connector)) {
                connector.close();
            }
        }
    }
}

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *