В этой статье я не буду рассказывать как создать 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();
}
}
}
}