[Info]Tags categorized posts and contents patterns..

[AJAX] Ajax Code E xamples.. [Book] About the book.. [CSS] CSS Code E xamples.. [DB] Sql Code E xamples.. [DEV] All development stor...

레이블이 MBean인 게시물을 표시합니다. 모든 게시물 표시
레이블이 MBean인 게시물을 표시합니다. 모든 게시물 표시

2017년 3월 2일 목요일

[Spring 레퍼런스] 23장 JMX #2..


출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

이 문서는 개인적인 목적이나 배포하기 위해서 복사할 수 있다. 출력물이든 디지털 문서든 각 복사본에 어떤 비용도 청구할 수 없고 모든 복사본에는 이 카피라이트 문구가 있어야 한다.

23.4 빈의 ObjectName 제어

내부적으로 MBeanExporter는 ObjectNamingStrategy 구현체에 등록하는 각 빈의 ObjectName을 가져오는 전략을 위임한다. 기본 구현체 KeyNamingStrategy는 beans Map의 키를 ObjectName로 사용한다. 그리고 KeyNamingStrategy는 beans Map의 키를 Properties의 항목에 매핑해서 ObjectName을 처리할 수 있다. KeyNamingStrategy외에도 스프링은 두 가지 ObjectNamingStrategy 구현체를 더 제공하고 있다. IdentityNamingStrategy는 빈의 JVM 아이디(identity)에 기반해서 ObjectName을 만들고 MetadataNamingStrategy은 소스수준의 메타데이터를 사용해서 ObjectName를 얻는다.

23.4.1 Properties에서 ObjectName 읽어오기

자신만의 KeyNamingStrategy 인스턴스를 설정해서 빈의 키를 사용하는 대신 Properties 인스턴스에서 ObjectName을 읽어오도록 구성할 수 있다. KeyNamingStrategy는 빈 키에 대응되는 키를 가진 Properties의 요소를 찾으려고 할 것이다. 일치하는 항목이 없거나 Properties 인스턴스가 null이라면 빈 키 자체를 사용한다. 아래 코드는 KeyNamingStrategy의 설정 예시를 보여준다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Xml

<beans>
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
      <map>
        <entry key="testBean" value-ref="testBean"/>
      </map>
    </property>
    <property name="namingStrategy" ref="namingStrategy"/>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>

  <bean id="namingStrategy" class="org.springframework.jmx.export.naming.KeyNamingStrategy">
    <property name="mappings">
      <props>
        <prop key="testBean">bean:name=testBean1</prop>
      </props>
    </property>
    <property name="mappingLocations">
      <value>names1.properties,names2.properties</value>
    </property>
  </bean>
</beans>

여기서 KeyNamingStrategy 인스턴스는 매핑 프로퍼티와 매핑 프로퍼티에 정의된 경로에 있는 프로퍼티 파일로 정의된 Properties 인스턴스와 합쳐진 Properties 인스턴스로 구성된다. 이 구성에서 testBean 빈은 ObjectName bean:name=testBean1을 받을 것이다. 이는 이 값이 Properties 인스턴스에서 빈 키에 대응되는 키를 가진 항목이기 때문이다. Properties 인스턴스에 항목이 없다면 빈 키의 이름을 ObjectName으로 사용한다.


23.4.2 MetadataNamingStrategy의 사용

MetadataNamingStrategy는 ObjectName을 사용하기 위해 각 빈의 ManagedResource속성의 objectName 프로퍼티를 사용한다. 아래 코드는 MetadataNamingStrategy의 설정 예시를 보여준다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Xml

<beans>
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
      <map>
        <entry key="testBean" value-ref="testBean"/>
      </map>
    </property>
    <property name="namingStrategy" ref="namingStrategy"/>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>

  <bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
    <property name="attributeSource" ref="attributeSource"/>
  </bean>

  <bean id="attributeSource" class="org.springframework.jmx.export.metadata.AttributesJmxAttributeSource"/>
</beans>

ManagedResource 속성에 제공된 objectName이 없다면 ObjectName은 [fully-qualified-package-name]:type=[short-classname],name=[bean-name]의 형식으로 생성될 것이다. 예를 들어 다음 빈에 생성된 ObjectName은 com.foo:type=MyClass,name=myBean가 될 것이다.

1
2
3
Xml

<bean id="myBean" class="com.foo.MyClass"/>


23.4.3 <context:mbean-export/> 요소

Java 5 이상을 사용함다면 MBeanExporter의 편리한 하위 클래스 AnnotationMBeanExporter를 사용할 수 있다. 이 하위 클래스의 인스턴스를 정의하면 표준 자바 어노테이션 기반의 메타데이터를 항상 사용할 것이므로 (자동탐지도 항상 활성화된다) namingStrategy, assembler, attributeSource 설정이 더이상 필요없다. 게다가 스프링의 'context' 네임스페이스가 지원하는 더 간단한 분법도 가능하다. MBeanExporter 빈을 정의하는 대신 다음의 요소를 지정하면 된다.

1
2
3
Xml

<context:mbean-export/>

필요하다면 특정 MBean 서버에 대한 참조를 제공할 수도 있고 defaultDomain 속성 (AnnotationMBeanExporter의 프로퍼티)은 생성된 Mbean ObjectNames의 도메인의 대체값을 받는다. 이전 MetadataNamingStrategy 섹션에서 설명한대로 이는 정규화된 패키지명에 사용한다.

1
2
3
Xml

<context:mbean-export server="myMBeanServer" default-domain="myDomain"/>


Note
빈(bean) 클래스에서 JMX 어노테이션의 자동탐지와 함께 인터페이스 기반의 AOP 프록시는 사용하지 말아라. 인터페이스 기반의 프록시는 대상 클래스를 '숨기고' JMX가 관리하는 리소스 어노테이션도 숨긴다. 그러므로 이러한 경우에는 대상클래스(target-class) 프록시를 사용해야 한다. 나 등의 'proxy-target-class' 플래그를 설정하더라도 JMX 빈은 구동시 이를 경고없이 무시할 것이다.


23.5 JSR-160 커넥터

리모트 접근을 위해서 스프링 JMX 모듈은 서버측과 클라이언트측 커넥터를 생성하는 org.springframework.jmx.support 패키지에서 FactoryBean의 두가지 구현체를 제공한다.

23.5.1 서버측 커넥터

스프링 JMX가 JSR-160 JMXConnectorServer를 생성해서 구동하고 노출하게 하려면 다음 설정을 사용해라.

1
2
3
Xml

<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean"/>

기본적으로 ConnectorServerFactoryBean는 JMXConnectorServer을 "service:jmx:jmxmp://localhost:9875"에 바인딩해서 생성한다. 그러므로 serverConnector 빈은 MBeanServer를 localhost의 JMXMP 프로토콜과 9875 포트로 노출한다. JMXMP 프로토콜은 JSR-160 명세에 선택사항으로 나와 있다. 현재로써는 주요 오픈소스 JMX 구현체인 MX4J와 J2SE 5.0이 제공하는 구현체가 JMXMP를 지원하지 않는다.
다른 URL을 지정해서 JMXConnectorServer 자체를 MBeanServer에 등록하려면 serviceUrl과 ObjectName 프로퍼티를 각각 사용해라.

1
2
3
4
5
6
Xml

<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean">
  <property name="objectName" value="connector:name=rmi"/>
  <property name="serviceUrl" value="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector"/>
</bean>

ObjectName 프로퍼티를 설정하면 스프링이 해당 ObjectName의 MBeanServer에 커넥터를 자동으로 등록할 것이다. 다음 예제는 JMXConnector 생성시 ConnectorServerFactoryBean에 전달할 수 있는 전체 파라미터를 보여주고 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Xml

<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean">
  <property name="objectName" value="connector:name=iiop"/>
  <property name="serviceUrl" value="service:jmx:iiop://localhost/jndi/iiop://localhost:900/myconnector"/>
  <property name="threaded" value="true"/>
  <property name="daemon" value="true"/>
  <property name="environment">
    <map>
      <entry key="someKey" value="someValue"/>
    </map>
  </property>
</bean>

RMI에 기반한 커넥터를 사용한다면 이름 등록과정이 완료된 후 시작되도록 검색 서비스(tnameserv나 rmiregistry)가 필요하다. RMI로 원격 서비스를 내보내도록 스프링을 사용하고 있다면 스프링은 이미 RMI 레지스트리를 생성했을 것이다. RIM로 원격서비스를 내보내도록 하고 있지 않다면 다음의 설정을 사용해서 간단하게 레지스트리를 시작할 수 있다.

1
2
3
4
5
Xml

<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
  <property name="port" value="1099"/>
</bean>


23.5.2 클라이언트측 커넥터

원격 JSR-160를 사용하는 MBeanServer에 MBeanServerConnection를 생성하려면 다음과 같이 MBeanServerConnectionFactoryBean를 사용해라.

1
2
3
4
5
Xml

<bean id="clientConnector" class="org.springframework.jmx.support.MBeanServerConnectionFactoryBean">
  <property name="serviceUrl" value="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxrmi"/>
</bean>


23.5.3 Burlap/Hessian/SOAP에서의 JMX

JSR-160은 클라이언트와 서버간의 통신을 수행하는 방법에 확장포인트를 허용하고 있다. 앞의 예제는 JSR-160 명세에 명시된 의무적인 RMI 기반의 구현체(IIOP와 JRMP)와 (선택적인) JMXMP를 사용하고 있다. 다른 프로바이더나 JMX 구현체 (MX4J와 같은)를 사용해서 HTTP나 SSL등을 사용하는 SOAP, Hessian, Burlap같은 프로토콜의 장점을 취할 수 있다.

1
2
3
4
5
6
Xml

<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean">
  <property name="objectName" value="connector:name=burlap"/>
  <property name="serviceUrl" value="service:jmx:burlap://localhost:9874"/>
</bean>

앞의 예제에서는 MX4J 3.0.0을 사용했다. 자세한 내용은 MX4J 공식 문서를 참고해라.


23.6 프록시를 통한 MBean 접근

스프링 JMX에서는 로컬이나 원격 MBeanServer에 등록된 MBean 호출을 리라우팅하는 프록시를 생성할 수 있다. 이러한 프록시는 MBean과 상호작용할 수 있는 표준 자바 인터페이스를 제공한다. 다음 코드는 로컬 MBeanServer에서 동작 중인 MBean에 대한 프록시를 구성하는 방법을 보여준다.

1
2
3
4
5
6
Xml

<bean id="proxy" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
  <property name="objectName" value="bean:name=testBean"/>
  <property name="proxyInterface" value="org.springframework.jmx.IJmxTestBean"/>
</bean>

ObjectName: bean:name=testBean으로 등록된 MBean에 프록시가 생성된 것을 볼 수 있다. 프록시가 구현하는 인터페이스들은 proxyInterfaces 프로퍼티로 제어하고 이 인터페이스들의 메서드와 프로퍼티를 MBean의 동작과 속성으로 매핑하는 규칙은 InterfaceBasedMBeanInfoAssembler에서 사용한 규칙과 동일하다. MBeanProxyFactoryBean은 MBeanServerConnection로 접근할 수 있는 모든 MBean에 대해서 프록시를 생성할 수 있다. 기본적으로 로컬 MBeanServer를 사용하지만 이를 오버라이드해서 원격 MBean을 가리키는 프록시에 대한 원격 MBeanServer를 가리키는 MBeanServerConnection를 제공할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Xml

<bean id="clientConnector" class="org.springframework.jmx.support.MBeanServerConnectionFactoryBean">
  <property name="serviceUrl" value="service:jmx:rmi://remotehost:9875"/>
</bean>

<bean id="proxy" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
  <property name="objectName" value="bean:name=testBean"/>
  <property name="proxyInterface" value="org.springframework.jmx.IJmxTestBean"/>
  <property name="server" ref="clientConnector"/>
</bean>

위 예제에서 MBeanServerConnectionFactoryBean를 사용하는 원격 머신을 가리키는 MBeanServerConnection를 생성한 것을 볼 수 있다. server 프로퍼티로 이 MBeanServerConnection을 MBeanProxyFactoryBean에 전달한다. 생성한 프록시는 이 MBeanServerConnection를 사용해서 모든 호출을 MBeanServer로 보낼 것이다.


23.7 알림(Notification)

스프링의 JMX는 JMX 알림도 광범위하게 지원하고 있다.

23.7.1 알림에 대한 리스너 등록

스프링의 JMX는 다수의 MBean(이는 스프링의 MBeanExporter가 내보낸 MBean과 다른 메카니즘으로 등록된 MBean을 포함한다.)을 가진 다수의 NotificationListeners을 아주 쉽게 등록할 수 있도록 지원한다. 예제를 통해서 대상 MBean의 속성이 변경될 때마다 알림을 받는(Notification으로) 시나리오를 생각해 보자.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Java

package com.example;

import javax.management.AttributeChangeNotification;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;

public class ConsoleLoggingNotificationListener implements NotificationListener, NotificationFilter {

  public void handleNotification(Notification notification, Object handback) {
    System.out.println(notification);
    System.out.println(handback);
  }

  public boolean isNotificationEnabled(Notification notification) {
    return AttributeChangeNotification.class.isAssignableFrom(notification.getClass());
  }
}


Xml

<beans>
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
      <map>
        <entry key="bean:name=testBean1" value-ref="testBean"/>
      </map>
    </property>
    <property name="notificationListenerMappings">
      <map>
        <entry key="bean:name=testBean1">
          <bean class="com.example.ConsoleLoggingNotificationListener"/>
        </entry>
      </map>
    </property>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>
</beans>

위 설정에서 대상 MBean(bean:name=testBean1)이 JMX Notification를 브로드캐스트할 때마다 notificationListenerMappings 프로퍼티에 리스너로 등록한 ConsoleLoggingNotificationListener 빈이 알림을 받을 것이다. ConsoleLoggingNotificationListener 빈은 Notification의 응답으로 적절한 모든 액션을 받을 수 있다.
내보낸 빈과 리스너간의 연결로 빈 이름을 직접 사용할 수도 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Xml

<beans>
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
      <map>
        <entry key="bean:name=testBean1" value-ref="testBean"/>
      </map>
    </property>
    <property name="notificationListenerMappings">
      <map>
        <entry key="testBean">
          <bean class="com.example.ConsoleLoggingNotificationListener"/>
        </entry>
      </map>
    </property>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>
</beans>

MBeanExporter가 내보내는 모든 빈에 하나의 NotificationListener 인스턴스를 등록하고 싶다면 notificationListenerMappings 프로퍼티 맵의 엔트리에 키로 '*' (따옴표없이)를 와일드카드로 사용할 수 있다. 예를 들면 다음과 같다.

1
2
3
4
5
6
7
8
9
Xml

<property name="notificationListenerMappings">
  <map>
    <entry key="*">
      <bean class="com.example.ConsoleLoggingNotificationListener"/>
    </entry>
  </map>
</property>

반대로 해야 한다면(즉, MBean에 다수의 리스너를 등록한다면) notificationListeners 리스트 프로퍼티(그리고 notificationListenerMappings 프로퍼티에 대한 설정에)를 대신 사용해야 한다. 이 때 단일 MBean의 NotificationListener를 설정하는 대신 NotificationListenerBean 인스턴스를 설정해라. NotificationListenerBean은 NotificationListener와 ObjectName(또는 ObjectNames)을 은닉화하고 이는 MBeanServer에 등록된다. NotificationListenerBean은 NotificationFilter와 고급 JMX 알림 시나리오에서 사용할 수 있는 임의의 handback 객체같은 다수의 프로퍼티들도 은닉화한다. NotificationListenerBean 인스턴스를 사용할 때의 설정은 이전에 본 설정과 크게 다르지 않다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Xml

<beans>
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
      <map>
        <entry key="bean:name=testBean1" value-ref="testBean"/>
      </map>
    </property>
    <property name="notificationListeners">
      <list>
        <bean class="org.springframework.jmx.export.NotificationListenerBean">
          <constructor-arg>
            <bean class="com.example.ConsoleLoggingNotificationListener"/>
          </constructor-arg>
          <property name="mappedObjectNames">
            <list>
              <value>bean:name=testBean1</value>
            </list>
          </property>
        </bean>
      </list>
    </property>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>
</beans>

위의 예제는 첫 알림 예제와 같다. Notification이 발생할 때마다 handback 객체가 주어지고 해당 NotificationFilter로 관련없는 Notifications을 필터링하기를 원한다고 해보자. (handback 객체가 무엇이고 NotificationFilter가 무엇인지에 대해서는 JMX 명세서(1.2)의 'The JMX Notification Model' 부분을 참고하기 바란다.)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Xml

<beans>
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
      <map>
        <entry key="bean:name=testBean1" value-ref="testBean1"/>
        <entry key="bean:name=testBean2" value-ref="testBean2"/>
      </map>
    </property>
    <property name="notificationListeners">
      <list>
        <bean class="org.springframework.jmx.export.NotificationListenerBean">
          <constructor-arg ref="customerNotificationListener"/>
          <property name="mappedObjectNames">
            <list>
              <!-- 두 별개의 MBean에서 받은 알림을 처리한다 -->
              <value>bean:name=testBean1</value>
              <value>bean:name=testBean2</value>
            </list>
          </property>
          <property name="handback">
            <bean class="java.lang.String">
              <constructor-arg value="This could be anything..."/>
            </bean>
          </property>
          <property name="notificationFilter" ref="customerNotificationListener"/>
        </bean>
      </list>
    </property>
  </bean>

  
  <bean id="customerNotificationListener" class="com.example.ConsoleLoggingNotificationListener"/>

  <bean id="testBean1" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>

  <bean id="testBean2" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="ANOTHER TEST"/>
    <property name="age" value="200"/>
  </bean>
</beans>


23.7.2 알림 발행하기

스프링은 Notifications을 받기 위한 등록뿐 아니라 Notifications을 보내기위한 등록도 지원한다.


Note
이 부분은 MBeanExporter를 통해 MBean으로 노출된 스프링이 관리하는 빈에 대해서만 관련된 부분이다. 이미 존재하거나 사용자가 정의한 모든 MBean은 표준 JMX API를 사용해서 알림을 발행해야 한다.

스프링의 JMX 알림 발행 지원에서 핵심 인터페이스는 NotificationPublisher 인터페이스다. (org.springframework.jmx.export.notification 패키지에 정의되어 있다.) MBeanExporter 인스턴스를 통해서 MBean으로 내보내질 모든 빈은 NotificationPublisher 인스턴스에 접근할 수 있도록 NotificationPublisherAware 인터페이스를 구현할 수 있다. NotificationPublisherAware 인터페이스는 해당 빈이 Notifications을 발행하는데 사용할 수 있는 간단한 setter 메서드로 구현한 빈에 NotificationPublisher 인스턴스를 제공한다. NotificationPublisher 클래스의 Javadoc에 나온대로 NotificationPublisher 메카니즘으로 이벤트를 발행하면서 관리되고 있는 빈은 어떤 알림 리스너 등에 대해서도 상태관리를 책임지지 않는다. 스프링의 JMX 지원은 JMX 인프라스트럭처와 관련된 모든 이슈의 처리를 담당한다. 애플리케이션 개발자가 해야하는 일은 NotificationPublisherAware 인터페이스를 구현하고 제공된 NotificationPublisher 인스턴스를 사용해서 이벤트를 발행하는 것 뿐이다. 관리되는 빈이 MBeanServer에 등록된 후에 NotificationPublisher가 설정된다는 점에 주의해라.

NotificationPublisher 인스턴스의 사용은 아주 직관적이다. 그냥 Notification 인스턴스(또는 Notification의 적절한 하위클래스의 인스턴스)를 만들고 발행할 이벤트와 관련된 데이터로 알림을 만든 후 NotificationPublisher 인스턴스의 sendNotification(Notification)를 호출해서 Notification을 전달하면 된다. 아래의 간단한 예제를 보자. 이 시나리오에서 내보내진 JmxTestBean 인스턴스는 add(int, int)가 호출될 때마다 NotificationEvent를 발행할 것이다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Java

package org.springframework.jmx;

import org.springframework.jmx.export.notification.NotificationPublisherAware;
import org.springframework.jmx.export.notification.NotificationPublisher;
import javax.management.Notification;

public class JmxTestBean implements IJmxTestBean, NotificationPublisherAware {

  private String name;
  private int age;
  private boolean isSuperman;
  private NotificationPublisher publisher;

  // 다른 getter와 setter는 생략했다

  public int add(int x, int y) {
    int answer = x + y;
    this.publisher.sendNotification(new Notification("add", this, 0));
    return answer;
  }

  public void dontExposeMe() {
    throw new RuntimeException();
  }

  public void setNotificationPublisher(NotificationPublisher notificationPublisher) {
    this.publisher = notificationPublisher;
  }
}

NotificationPublisher 인터페이스와 관련된 부분이 모두 잘 동작한다는 점이 스프링의 JMX 지원을 좋은 점중 하나다. 하지만 클래스가 스프링과 JMX에 모두 의존성을 갖게 된다는 단점이 있다. 언제나 그렇듯이 이에 대한 조언은 현실적인 조언 뿐이다. NotificationPublisher이 제공하는 기능이 필요하고 스프링과 JMX에 대한 의존성을 받아들일 수 있다면 사용해도 좋다.


23.8 추가 자료

이 섹션에서는 JMX에 대한 추가자료와 관련된 링크를 제공한다.


2017년 2월 24일 금요일

[Spring 레퍼런스] 23장 JMX #1..


출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

이 문서는 개인적인 목적이나 배포하기 위해서 복사할 수 있다. 출력물이든 디지털 문서든 각 복사본에 어떤 비용도 청구할 수 없고 모든 복사본에는 이 카피라이트 문구가 있어야 한다.

23. JMX

23.1 소개

스프링은 스프링 어플리케이션을 JMX 인프라에 쉽고 투명하게 통합할 수 있도록 지원한다.
특히 스프링의 JMX 지원은 네 가지 핵심 기능을 제공한다.
  • 어떤 스프링 빈이라도 JMX MBean으로 자동 등록
  • 빈 관리 인터페이스를 제어하는 유연한 메커니즘
  • 선언적으로 원격(JSR-160 커넥터)에 MBean을 노출
  • 로컬/원격 MBean 리소스를 간단하게 프록시 함
이 기능들은 애플리케이션 컴포넌트가 스프링이나 JMX 인터페이스 혹은 클래스에 의존하지 않고 동작하도록 설계되었다. 사실 애플리케이션 클래스 대부분은 스프링의 JMX 좋은 기능을 위해서 스프링이나 JMX를 인지할 필요가 없다.


JMX?
이번 장은 JMX를 소개하는 장이 아니므로 왜 JMX가 필요한가에 대해서는 설명하지 않는다(또는 JMX가 무엇의 약자인지) JMX를 처음 본다면 이 장 마지막의 Section 23.8, “추가 자료”를 봐라.


23.2 빈을 JMX에 내보내기

MBeanExporter이 스프링 JMX 프레임워크의 핵심 클래스다. MBeanExporter이 스프링 빈을 가져와서 JMX MBeanServer에 등록한다. 예시로 다음 클래스를 생각해 보자.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Java

package org.springframework.jmx;

public class JmxTestBean implements IJmxTestBean {
  private String name;
  private int age;
  private boolean isSuperman;

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public int add(int x, int y) {
    return x + y;
  }

  public void dontExposeMe() {
    throw new RuntimeException();
  }
}

이 빈의 프로퍼티와 메서드를 MBean의 속성과 오퍼레이션으로 노출하려면 다음과 같이 설정파일에 MBeanExporter 클래스의 인스턴스를 설정하고 빈을 전달하면 된다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Xml

<beans>
  
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
    <property name="beans">
      <map>
        <entry key="bean:name=testBean1" value-ref="testBean"/>
      </map>
    </property>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>
</beans>

위 설정 예시에서 적절한 빈 정의는 exporter 빈이다. beans 프로퍼티가 빈 중에 정확히 어떤 빈을 JMX MBeanServer에 내보내야야 하는지 MBeanExporter에 알려준다. 기본 설정에서 beans Map의 각 요소의 키를 해당 값이 참조하는 빈의 ObjectName으로 사용한다. Section 23.4, “빈의 ObjectName 제어”에서 설명했듯이 이 동작은 변경할 수 있다.
이 설정에서 testBean 빈은 ObjectName bean:name=testBean1의 MBean으로 노출한다. 기본적으로 빈의 모든 public 프로퍼티는 속성(attribute)로 노출하고 public 메서드 (Object 클래스에서 상속받은 메서드 포함)는 오퍼레이션으로 노출한다.

23.2.1 MBeanServer 생성

위의 설정은 하나의(유일한) MBeanServer가 동작하고 있는 환경에서 어플리케이션이 돌아가고 있다고 가정한다. 이러한 경우 스프링은 돌아가고 있는 MBeanServer을 찾아내서 (찾았다면)해당 서버에 빈을 등록하려고 할 것이다. Tomcat이나 IBM WebSphere처럼 MBeanServer를 가진 컨테이너에서 어플리케이션을 돌리는 경우 이 동작이 유용하다.
하지만 독립적인 환경이나 MBeanServer를 제공하지 않는 컨테이너를 사용하는 경우에는 이 접근을 사용하지 않는다. 설정에 org.springframework.jmx.support.MBeanServerFactoryBean 클래스의 인스턴스를 추가해서 선언적으로 MBeanServer 인스턴스를 생성해서 이 문제를 해결할 수 있다. MBeanExporter의 server 프로퍼티를 MBeanServerFactoryBean이 반환한 MBeanServer 값으로 설정해서 특정 MBeanServer를 사용한다는 것을 보장할 수도 있다. 예를 들면 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Xml

<beans>
  <bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>

  
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
      <map>
        <entry key="bean:name=testBean1" value-ref="testBean"/>
      </map>
    </property>
    <property name="server" ref="mbeanServer"/>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>
</beans>

여기서 MBeanServerFactoryBean이 MBeanServer의 인스턴스를 생성했고 server 프로퍼티로 MBeanExporter에 전달했다. 자신의 MBeanServer 인스턴스를 전달했을 때 MBeanExporter가 동작하고 있는 MBeanServer를 찾지 않고 전달받은 MBeanServer 인스턴스를 사용할 것이다. 이 부분이 제대로 동작하려면 클래스패스에 JMX 구현체가 당연히 있어야 한다.


23.2.2 이미 존재하는 MBeanServer의 재사용

서버를 지정하지 않으면 자동으로 MBeanExporter가 돌아가고 있는 MBeanServer를 탐지하려고 할 것이다. 딱 하나의 MBeanServer 인스턴스만 사용하는 대부분의 환경에서는 잘 동작할 것이지만 여러 인스턴스가 존재한다면 익스포터가 잘못된 서버를 선택할 수도 있다. 이러한 경우 사용할 인스턴스를 나타내는 MBeanServer agentId를 사용해야 한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Xml

<beans>
   <bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
     <!-- 제일 먼저 찾을 서버를 지정한다 -->
     <property name="locateExistingServerIfPossible" value="true"/>
     <!-- 주어진 agentId로 MBeanServer 인스턴스를 찾는다 -->
     <property name="agentId" value="<MBeanServer instance agentId>"/>
   </bean>

   <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
     <property name="server" ref="mbeanServer"/>
   ...
   </bean>
</beans>

기존의 MBeanServer가 검색 메서드로 얻은 동적(혹은 모르는) agentId를 가진 경우는 factory-method를 사용해야 한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Xml

<beans>
   <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
     <property name="server">
       <!-- 커스텀 MBeanServerLocator -->
       <bean class="platform.package.MBeanServerLocator" factory-method="locateMBeanServer"/>
     </property>

     <!-- 다른 빈 정의 -->
   </bean>
</beans>


23.2.3 지연 초기화된 MBean

지연 초기화로 설정된 MBeanExporter로 지연 초기화된 빈을 설정하는 경우 MBeanExporter이 해당 규약을 깨뜨리지 않을 것이고 빈을 인스턴스화하지 않을 것이다. 대신 MBeanExporter는 MBeanServer에 프록시를 등록하고 프록시에서 첫 호출이 발생할 때까지 컨테이너에서 빈을 가져오는 것을 미룰 것이다.

23.2.4 MBean의 자동 등록

MBeanExporter로 익스포트했고 유효한 MBean인 모든 빈은 스프링이 추가적으로 개입하지 않고 그대로 MBeanServer에 등록된다. autodetect 프로퍼티를 true로 설정해서 MBeanExporter가 자동으로 MBean을 탐지할 수 있다.

1
2
3
4
5
6
7
Xml

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
  <property name="autodetect" value="true"/>
</bean>

<bean name="spring:mbean=true" class="org.springframework.jmx.export.TestDynamicMBean"/>

이 예제에서 spring:mbean=true인 빈은 이미 유효한 JMX MBean이고 스프링이 자동으로 등록할 것이다. 기본적으로 JMX에 자동탐지되서 등록한 빈은 ObjectName을 빈 이름으로 사용한다. 이 동작은 Section 23.4, “빈의 ObjectName 제어”에서 설명한대로 변경할 수 있다.


23.2.5 등록과정의 제어

스프링 MBeanExporter가 'bean:name=testBean1'이라는 ObjectName으로 MBeanServer에 MBean을 등록하려고 하는 시나리오를 생각해 보자. MBean 인스턴스가 이미 같은 ObjectName으로 등록되어 있다면 기본 동작은 실패한다. (InstanceAlreadyExistsException를 던진다.)
MBean을 MBeanServer에 등록했을 때 일어나는 동작을 제어할 수 있다. 스프링의 JMX 지원으로 등록과정에서 MBean이 이미 같은 ObjectName으로 등록되었다는 점을 발견했을 때 등록 동작을 제어할 수 있는 세가지 등록 동작을 이용할 수 있다. 이 등록 동작은 다음 표에 정리되어 있다.

Table 23.1. 등록 동작
등록 동작설명
REGISTRATION_FAIL_ON_EXISTING기본 등록 동작이다. MBean 인스턴스가 같은 ObjectName으로 이미 등록되어 있다면 등록하려던 MBean을 등록하지 않고 InstanceAlreadyExistsException를 던질 것이다. 존재하는 MBean에는 영향을 주지 않는다.
REGISTRATION_IGNORE_EXISTINGMBean 인스턴스가 같은 ObjectName으로 이미 등록되어 있다면 등록하려던 MBean을 등록하지 않는다. 기존의 MBean에는 영향을 주지 않고 Exception도 던지지 않는다.
이 동작은 공유된 MBeanServer에서 여러 어플리케이션이 공통적인 MBean을 공유할 때 유용하다.
REGISTRATION_REPLACE_EXISTINGMBean 인스턴스가 같은 ObjectName으로 이미 등록되어 있다면 미리 등록되어 있던 MBean이 등록 해지되고 새로운 MBean이 해당 위치에 등록될 것이다. (이전의 인스턴스를 새로운 MBean이 효율적으로 바꿔치기 한다.)












위의 값은 MBeanRegistrationSupport 클래스(MBeanExporter 클래스는 이 수퍼클래스에서 파생된 클래스다.)에 상수로 정의되어 있다. 기존 등록동작을 바꾸고자 한다면 MBeanExporter 정의에서 registrationBehaviorName 프로퍼티의 값을 변경하면 된다.
다음 예제는 기본 등록 동작을 REGISTRATION_REPLACE_EXISTING로 변경이 어떻게 영향을 주는지 보여준다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Xml

<beans>
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
      <map>
        <entry key="bean:name=testBean1" value-ref="testBean"/>
      </map>
    </property>
    <property name="registrationBehaviorName" value="REGISTRATION_REPLACE_EXISTING"/>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>
</beans>


23.3 빈의 관리 인터페이스 제어하기

이전 예제에서 빈의 관리(management) 인터페이스로 약간의 제어를 했다. 익스포트한 모든 public 프로퍼티와 메서드는 JMX 속성과 동작으로 각각 노출된다. 익스포트한 빈의 어떤 프로퍼티와 메서드가 JMX 속성과 동작으로 노출되는지 세밀하게 제어하기 위해서 스프링 JMX는 빈의 관리 인터페이스를 제어하는 광범위하고 확장가능한 메카니즘을 제공한다.

23.3.1 MBeanInfoAssembler 인터페이스

내부적으로 MBeanExporter는 노출될 각 빈의 관리 인터페이스를 정의하는 역할을 하는 org.springframework.jmx.export.assembler.MBeanInfoAssembler 인터페이스의 구현체에 위임한다. 기본 구현체인 org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler는 모든 퍼블릭 프로퍼티와 메서드를 노출하는(이전 예제에서 본 것처럼) 관리 인터페이스를 정의한다. 스프링은 소스수준의 메타데이터나 다른 임의의 인터페이스를 사용해서 생성한 관리 인터페이스를 제어할 수 있는 MBeanInfoAssembler 인터페이스의 두 구현체를 추가적으로 제공한다.

23.3.2 소스 수준의 메타데이터 사용하기 (JDK 5.0 어노테이션)

MetadataMBeanInfoAssembler를 사용해서 소스 수준의 메타데이터를 사용하는 빈에 대한 관리 인터페이스를 정의할 수 있다. 메타데이터는 org.springframework.jmx.export.metadata.JmxAttributeSource 인터페이스로 캡슐화해서 읽는다. 스프링 JMX는 JDK 5.0 어노테이션 (org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource)을 사용하는 기본 구현체를 제공한다. MetadataMBeanInfoAssembler가 제대로 동작하기 위해서는 JmxAttributeSource 인터페이스의 구현체 인스턴스로 설정해야 한다.(기본값이 존재하지 않는다.)
JMX로 내보내도록 빈을 표시하려면 빈 클래스에 ManagedResource 어노테이션을 붙혀야 한다. 동작(operation)으로 노출하려는 각 메서드는 ManagedOperation 어노테이션을 붙혀야 하고 노출하려는 각 프로퍼티는 ManagedAttribute 어노테이션을 붙혀야 한다. 프로퍼티에 어노테이션을 붙힐 때는 읽기 전용이나 쓰기 전용 속성을 만들기 위해서 getter나 setter의 어노테이션을 생략할 수 있다. 아래 예제는 앞에서 본 JmxTestBean 클래스의 어노테이션을 사용한 버전이다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Java

package org.springframework.jmx;

import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedAttribute;

@ManagedResource(objectName="bean:name=testBean4", description="My Managed Bean", log=true,
    logFile="jmx.log", currencyTimeLimit=15, persistPolicy="OnUpdate", persistPeriod=200,
    persistLocation="foo", persistName="bar")
public class AnnotationTestBean implements IJmxTestBean {

  private String name;
  private int age;

  @ManagedAttribute(description="The Age Attribute", currencyTimeLimit=15)
  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  @ManagedAttribute(description="The Name Attribute",
      currencyTimeLimit=20,
      defaultValue="bar",
      persistPolicy="OnUpdate")
  public void setName(String name) {
    this.name = name;
  }

  @ManagedAttribute(defaultValue="foo", persistPeriod=300)
  public String getName() {
    return name;
  }

  @ManagedOperation(description="Add two numbers")
  @ManagedOperationParameters({
    @ManagedOperationParameter(name = "x", description = "The first number"),
    @ManagedOperationParameter(name = "y", description = "The second number")})
  public int add(int x, int y) {
    return x + y;
  }

  public void dontExposeMe() {
    throw new RuntimeException();
  }
}

이 예제에서 JmxTestBean 클래스에 ManagedResource 어노테이션이 붙어있는 것을 볼 수 있고 이 ManagedResource 어노테이션은 여러 가지 프로터티들로 설정되어 있다. MBeanExporter가 생성하는 MBean의 다양한 관점을 설정하는데 이러한 프로퍼티를 설정할 수 있고 더 자세한 내용은 나중에 Section 23.3.3, “소스 수준의 메타데이터 타입”부분에서 설명한다.
age와 name 프로퍼티도 ManagedAttribute 어노테이션이 붙을 것을 볼 수 있는데 여기서 age에는 getter에만 어노테이션이 붙어 있다. 이 어노테이션을 붙힘으로써 두 프로퍼티 모두 관리 인터페이스의 속성으로 포함되지만 age는 읽기 전용이다. 마지막으로 add(int, int) 메서드에는 ManagedOperation 어노테이션이 붙어있지만 dontExposeMe() 메서드에는 붙어있지 않다. 그래서 관리 인터페이스는 MetadataMBeanInfoAssembler를 사용할 때 add(int, int) 오퍼레이션만 가진다.
MetadataMBeanInfoAssembler를 사용하는 MBeanExporter를 설정하는 방법이 아래 설정에 나와 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Xml

<beans>
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="assembler" ref="assembler"/>
    <property name="namingStrategy" ref="namingStrategy"/>
    <property name="autodetect" value="true"/>
  </bean>

  <bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>

  
  <bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
    <property name="attributeSource" ref="jmxAttributeSource"/>
  </bean>

  
  
  <bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
    <property name="attributeSource" ref="jmxAttributeSource"/>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.AnnotationTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>
</beans>

여기서 MetadataMBeanInfoAssembler 빈이 AnnotationJmxAttributeSource 클래스의 인스턴스로 설정되었고 assembler 프로퍼티로 MBeanExporter에 전달되는 것을 볼 수 있다. 이것이 스프링이 노출한 MBean의 메타데이터 주도 관리 인터페이스의 장점을 취하기 위해서 필요한 전부이다.


23.3.3 소스 수준의 메타데이터 타입

다음 소스수준의 메타데이터 타입을 스프링 JMX에서 사용할 수 있다.

Table 23.2. 소스 수준의 메타데이터 타입
목적어노테이션어노테이션 타입
Class의 모든 인스턴스를 JMX가 관리하는 리소스로 표시한다.@ManagedResourceClass
메서드를 JMX 동작으로 표시한다.@ManagedOperationMethod
getter나 setter를 JMX 속성의 절반으로 표시한다.@ManagedAttributeMethod (getter와 setter 전용)
동작(operation) 파라미터에 대한 디스크립션을 정의한다.@ManagedOperationParameter와 @ManagedOperationParametersMethod





소스 수준의 메타데이터 타입에서 다음 설정 파라미터를 사용할 수 있다.

Table 23.3. 소스 수준의 메타데이터 파라미터
파라미터설명적용 대상
ObjectName관리하는 리소스의 ObjectName을 결정하기 위해서 MetadataNamingStrategy가 사용한다.ManagedResource
description리소스, 속성, 동작의 디스크립션을 설정한다.ManagedResource, ManagedAttribute, ManagedOperation, ManagedOperationParameter
currencyTimeLimitcurrencyTimeLimit 디스크립터 필드의 값을 설정한다ManagedResource, ManagedAttribute
defaultValuedefaultValue 디스크립터 필드의 값을 설정한다ManagedAttribute
loglog 디스크립터 필드의 값을 설정한다ManagedResource
logFilelogFile 디스크립터 필드의 값을 설정한다ManagedResource
persistPolicypersistPolicy 디스크립터 필드의 값을 설정한다ManagedResource
persistPeriodpersistPeriod 디스크립터 필드의 값을 설정한다ManagedResource
persistLocationpersistLocation 디스크립터 필드의 값을 설정한다ManagedResource
persistNamepersistName 디스크립터 필드의 값을 설정한다ManagedResource
name동작(operation) 파라미터의 표시 이름을 설정한다ManagedOperationParameter
index동작 파라미터의 인덱스를 설정한다ManagedOperationParameter


















23.3.4 AutodetectCapableMBeanInfoAssembler 인터페이스

더 간단한 설정을 위해서 스프링은 MBeanInfoAssembler 인터페이스를 확장해서 MBean 리소스를 자동탐지를 지원하려고 AutodetectCapableMBeanInfoAssembler 인터페이스를 도입했다. AutodetectCapableMBeanInfoAssembler 인스턴스로 MBeanExporter를 설정하면 JMX에 노출하기 위해 빈에 "투표(vote)"할 수 있다.
AutodetectCapableMBeanInfo 인터페이스의 유일한 구현체인 MetadataMBeanInfoAssembler는 ManagedResource 속성으로 표시된 모든 빈을 포함하도록 투표한다. 이 경우 기본 접근은 다음과 같은 설정의 빈 이름을 ObjectName으로 사용하는 것이다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Xml

<beans>
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <!-- 어떤 'beans'도 명시적으로 선언하지 않았다. -->
    <property name="autodetect" value="true"/>
    <property name="assembler" ref="assembler"/>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>

  <bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
    <property name="attributeSource">
        <bean class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
    </property>
  </bean>
</beans>

이 설정에서 어떤 빈도 MBeanExporter에 전달하지 않았다. 하지만 ManagedResource 속성으로 표시되었고 MetadataMBeanInfoAssembler가 ManagedResource를 탐지해서 포함시키도록 투표하므로 JmxTestBean가 등록될 것이다. 이 접근방법의 유일한 문제점은 JmxTestBean의 이름이 비즈니스적인 의미를 갖게 되었다는 점이다. Section 23.4, “빈의 ObjectName 제어”에서 정의된 것처럼 ObjectName를 생성하는 기본 동작을 변경해서 이 문제를 해결할 수 있다.


23.3.5 자바 인터페이스를 사용한 관리 인터페이스 정의

MetadataMBeanInfoAssembler에 추가적으로 스프링도 인터페이스 컬렉션에 정의된 메서드 세트에 기반해서 노출되는 메서드와 프로퍼티에 제약을 가할 수 있는 InterfaceBasedMBeanInfoAssembler를 포함하고 있다.
MBean을 노출하는 표준 메카니즘이 인터페이스와 간단한 작명 계획을 사용하기는 하지만 InterfaceBasedMBeanInfoAssembler는 작명 관례에 대한 요구사항을 제거해서 이 기능을 확장함으로써 하나 이상의 인터페이스를 사용하고 빈이 MBean 인터페이스를 구현하지 않다도 되게 한다.
앞에서 본 JmxTestBean 클래스에 대한 관리 인터페이스를 정의할 때 이 인터페이스의 사용을 고려해 봐라.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Java

public interface IJmxTestBean {

  public int add(int x, int y);

  public long myOperation();

  public int getAge();

  public void setAge(int age);

  public void setName(String name);

  public String getName();
}

이 인터페이스는 JMX MBean의 동작과 속성으로 노출될 메서드와 프로퍼티를 정의한다. 아래 코드는 관리 인터페이스의 정의로 이 인터페이스를 사용하도록 스프릥 JMX를 설정하는 방법을 보여준다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Xml

<beans>
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
      <map>
        <entry key="bean:name=testBean5" value-ref="testBean"/>
      </map>
    </property>
    <property name="assembler">
      <bean class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
        <property name="managedInterfaces">
          <value>org.springframework.jmx.IJmxTestBean</value>
        </property>
      </bean>
    </property>
  </bean>

  <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
    <property name="name" value="TEST"/>
    <property name="age" value="100"/>
  </bean>
</beans>

모든 빈에 대한 관리 인터페이스를 생성할 때 IJmxTestBean 인터페이스를 사용하도록 설정한 InterfaceBasedMBeanInfoAssembler를 볼 수 있다. InterfaceBasedMBeanInfoAssembler가 처리한 빈은 JMX 관리 인터페이스를 생성하는데 사용하는 인터페이스를 구현할 필요가 없다는 점을 이해하는 것이 중요하다.
위의 경우 모든 빈에 대한 모든 관리 인터페이스를 생성하는데 IJmxTestBean 인터페이스를 사용한다. 많은 경우 이는 원하는 동작이 아니고 빈마다 다른 인터페이스를 사용하길 원할 것이다. 이러한 경우에는 interfaceMappings 프로퍼티로(각 엔트리는 빈의 이름이고 엔트리의 값은 해당 빈에 사용할 인터페이스 이름을 콤마로 구분한 목록이다.) InterfaceBasedMBeanInfoAssembler Properties 인스턴스를 전달할 수 있다.
managedInterfaces와 interfaceMappings 프로퍼티로 지정한 관리 인터페이스가 없으면 InterfaceBasedMBeanInfoAssembler가 빈에 반영되고 관리인터페이스를 생성하는 해당 빈이 구현한 모든 인터페이스를 사용할 것이다.

23.3.6 MethodNameBasedMBeanInfoAssembler 사용하기

MethodNameBasedMBeanInfoAssembler로 JMX가 속성과 동작으로 노출할 메서드명의 목록을 지정할 수 있다. 아래 코드는 이에 대한 설정 예시를 보여 준다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Xml

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
  <property name="beans">
    <map>
      <entry key="bean:name=testBean5" value-ref="testBean"/>
    </map>
  </property>
  <property name="assembler">
    <bean class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler">
      <property name="managedMethods">
        <value>add,myOperation,getName,setName,getAge</value>
      </property>
    </bean>
  </property>
</bean>

이 코드에서 add와 myOperation 메서드가 JMX 동작으로 노출되고 getName(), setName(String), getAge()는 JMX 속성으로 노출되는 것을 볼 수 있다. 위 코드에서 메서드는 JMX에 노출되는 빈에 매핑된다. 빈과 빈(bean-by-bean)의 메서드 노출을 제어하려면 빈 이름을 메서드 이름의 목록에 매핑하기 위해 MethodNameMBeanInfoAssembler의 methodMappings 프로퍼티를 사용해라.