본문 바로가기

WEB개발/JAVA

JMX(MBean), JOLOKIA

JMX(Java Management Extensions)

 JMX(Java Management eXtensions)는 응용 프로그램(소프트웨어)/객체/장치 (프린터 등) 및 서비스 지향 네트워크 등을 감시 관리를 위한 도구를 제공하는 자바 API이다. 

 

 JDK 1.5 이상부터 기본적으로 탑재된 기능 자바 어플리케이션의 모니터링과 관리 기능을 제공한다. Non-Java Resource와 하드웨어에 대해 wrapping한 인터페이스를 제공하며, API를 외부로 노출해 application 설정 및 통계데이터를 수집할 수 있는 기능을 제공한다.
 

mBean으로 알려진 하나 이상의 사용자 JavaBean 오브젝트를 통해(혹은 리소스를 호출하는) 애플리케이션, 디바이스, 서비스를 원격으로 제어할 수 있다.

mBean들은 mBean 서버에 등록되며, mBean 서버는 리소스에 접근하는 모든 원격 매니저를 관리한다.

 

  1. MBean(Managed Bean) 플랫폼 혹은 사용자에 의해 만들어진 모니터링용 객체.
  2. Standard MBean, Dynamic MBean, Model MBean, Open MBean 4가지 종류로 나뉨
  3. MBean Server : MBean을 등록. MBeans를 모니터링하기 원하는 원격 JMX 관리자는 MBean Server를 통하여 정보를 획득
  4. agent service : MBeans를 관리하는 (개발자가 제작한) 서비스 - client

MXBean( Managed Extended Bean )은 Java Management Extensions (JMX)의 일부로, JMX 프로토콜을 사용합니다. JMX 프로토콜은 Java 애플리케이션에서 모니터링 및 관리를 위한 표준화된 방법을 제공합니다.

 

 

RMI(Remote Method Invocation)는 기본적으로 TCP/IP 프로토콜을 사용하여 통신합니다. RMI는 자바에서 분산 객체 호출을 처리하는 메커니즘으로, 원격 서버에서 객체의 메서드를 로컬 객체처럼 호출할 수 있도록 해줍니다.
RMI의 통신 방식은 다음과 같습니다

1. 객체 전송: RMI는 원격 객체의 메서드를 호출하기 위해 네트워크를 통해 객체와 데이터를 전송합니다. 이 과정에서 기본적으로 TCP/IP를 사용하여 데이터가 송수신됩니다.

2. RMI 레지스트리: RMI는 "RMI 레지스트리"라는 서비스를 통해 원격 객체를 찾습니다. 클라이언트가 원격 객체를 호출하려면 먼저 RMI 레지스트리에서 객체를 조회한 후, TCP/IP 프로토콜을 통해 원격 객체와의 연결을 설정합니다.

3.RMI 통신: 원격 객체의 메서드를 호출할 때, 호출은 TCP/IP 네트워크를 통해 전달됩니다. Java RMI는 내부적으로 TCP/IP 기반의 소켓을 이용해 객체와 메서드 호출 정보를 전송하고, 그 결과를 클라이언트로 되돌려 보냅니다.


JMX 프로토콜은 RMI (Remote Method Invocation) 프로토콜을 기반으로 하며, 원격으로 JMX MBean을 연결하고 접근할 수 있도록 합니다. RMI는 자바 애플리케이션 간에 객체를 직접 주고받을 수 있도록 해주는 기술입니다.

따라서, MXBean은 RMI 프로토콜을 사용하여 JMX 서버와 클라이언트 사이의 통신을 처리하며, 자바 애플리케이션 간에 객체를 주고받을 수 있도록 합니다.

 

 

클래스명: BeanObj
인터페이스: BeanObjMXBean

쌍이 있어야 JMX가 자동으로 “이건 MXBean이다”라고 인식함.

package org.example;

public interface BeanObjMXBean {
    String getMessage();
    void setMessage(String message);
}



package org.example;


import javax.management.*;
import java.util.concurrent.atomic.AtomicLong;

public class BeanObj extends NotificationBroadcasterSupport
        implements BeanObjMXBean {

    private String message = "init";
    private final AtomicLong seq = new AtomicLong(1);

    @Override
    public synchronized void setMessage(String message) {

        Notification n = new AttributeChangeNotification(
                this,
                seq.getAndIncrement(),
                System.currentTimeMillis(),
                "message changed",
                "Message",
                "java.lang.String",
                this.message,
                message
        );

        this.message = message;
        sendNotification(n); // 🔔 이벤트 발생
    }

    @Override
    public synchronized String getMessage() {
        return message;
    }
}

 

public class MyMXBeanImpl implements MyMXBean {
   private String message;
   
   @Override
   public void setMessage(String msg) {
      message = msg;
   }
   
   @Override
   public String getMessage() {
      return message;
   }
}
package org.example;

import javax.management.AttributeChangeNotification;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import java.lang.management.ManagementFactory;
import java.nio.charset.StandardCharsets;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class MxBeanServer {
    public static void main(String[] args) throws Exception {
        // MBeanServer 생성
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

        // JMX 커넥터 생성
        String host = "127.0.0.1"; // 서버 IP 주소
        int port = 9999; // 서버 포트 번호

        // Rmi registry에 서버 IP, port를 설정한다.
        Registry registry = LocateRegistry.createRegistry(port);

        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/server");
        JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);

        // 커넥터 시작
        connector.start();

        // MBean 등록
        ObjectName mxbeanName = new ObjectName("jmx:type=MXBean");
        BeanObj mxbean = new BeanObj();
        mbs.registerMBean(mxbean, mxbeanName);

        // 클라이언트 요청 대기
        System.out.println("MXBean Server started, waiting for client requests...");

        // 🔔 변경 감지 리스너
        mbs.addNotificationListener(mxbeanName, (notification, handback) -> {
            if (notification instanceof AttributeChangeNotification acn) {
                System.out.println("MXBean 변경됨!");
                System.out.println("ATTR:   " + acn.getAttributeName());
                System.out.println("OLD VALUE: " + acn.getOldValue());
                System.out.println("NEW VALUE: " + acn.getNewValue());
            }
        }, null, null);
        Thread.sleep(Long.MAX_VALUE);
    }
}
package org.example;

import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class MxBeanClient {

    public static void main(String[] args) throws Exception {
        String host = "localhost"; // 서버 IP 주소
        int port = 9999; // 서버 포트 번호
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/server");
        JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
        MBeanServerConnection mBeanServerConnection = jmxc.getMBeanServerConnection();

        ObjectName mxbeanname = new ObjectName("jmx:type=MXBean");
        BeanObjMXBean bean = JMX.newMXBeanProxy(mBeanServerConnection, mxbeanname, BeanObjMXBean.class);

        bean.setMessage("hello");
        jmxc.close();
    }


}

Jolokia

Jolokia는 JMX MBean을 HTTP/JSON 기반 REST API로 노출하는 에이전트이다.

이를 통해 JMX를 RMI 대신 HTTP로 접근할 수 있어, 방화벽·NAT·보안 설정이 단순해진다.

 

public class MyMXBeanClient {
   public static void main(String[] args) throws Exception {
      // Jolokia Client 생성
      String host = "localhost"; // 서버 IP 주소
      int port = 8080; // 서버 포트 번호
      
      System.out.println(new URL("http", host, port, "").toString());
      
      J4pClient j4pClient = new J4pClient(new URL("http", host, port, "").toString());

      // MXBean 데이터 조회
      J4pReadRequest request = new J4pReadRequest("com.app.woo.jmx:type=MyMXBean", "Message");
      J4pReadResponse response = j4pClient.execute(request);

      // JSON 데이터 파싱
      Object value = response.getValue();
      if (value instanceof JSONObject) {
         JSONObject jsonObject = (JSONObject)value;
         String message = (String)jsonObject.get("Message");
         System.out.println("Message: " + message);
      }
   }
}

 

dependencies {
    implementation 'org.jolokia:jolokia-core:1.7.1'
    implementation 'org.jolokia:jolokia-jvm:1.7.1'
}

 

 

 


https://ko.wikipedia.org/wiki/JMX