MX4J 구현과 상호작용하기(interacting)

MX4J 구현은 몇가지 내부 기능을 MBean과 어플리케이션에서 사용할 수 있는 공개 API를 통해 호출할 수 있다.
그러나 이 API를 사용하게 되면 MBean이나 MX4J 구현을 이용한 어플리케이션과 밀접하게 연관이 되어있어서, 이것들을 다른 JMX 구현으로 이동이 불가능해질(non-portable) 것이다.

내부 logging 전송

MX4J는 로그 우선순위를 조정할 수 있게 하며, MX4J의 내부 로그를 Log4J와 같은 로깅 시스템으로 redirect할 수 있는 기능을 가지는 매우 유연한 로깅 시스템을 가지고 있다.

MX4J 로깅 시스템은 여섯개의 로깅 순위가 있다. 낮은 우선 순위부터 높은 순위로 적는다.

  • trace

  • debug

  • info

  • warn

  • error

  • fatal

기본 설정 레벨은 warn이고, "mx4j.log.priority" 시스템 속성의 값을 위의 값들 중에 하나로 세팅하여 설정을 변경할 수 있다.

예를 들어, JVM의 명령행에서 MX4J 로그를 debug 레벨로 변경하려면 :

java -Dmx4j.log.priority=debug MyMainClass

fatal 레벨은 MX4J에서는 사용되지 않는다.

MX4J 기본 로깅은 System.out을 통해 콘솔로 출력된다. 그러나 MX4J 로깅 API를 사용하거나, broadcater MBean(아래에)을 사용하여, 다른 로깅 시스템으로 redirect할 수 있다.

예를 들어, MX4J의 로깅을 Log4J로깅 시스템으로 redirect하고자 한다면, 아래 코드가 해야 할 일이다.

예 2.7. Log4J로 로깅 Redirection

		
import org.apache.log4j.PropertyConfigurator;
import mx4j.log.*;

public class Main
{
	public static void main(String[] args) throws Exception
	{
		// Configure Log4J
		PropertyConfigurator.configureAndWatch("log4j.properties");
		// Or use the XML version below
		// DOMConfigurator.configureAndWatch("log4j.xml");

		// Redirect MX4J logging to Log4J
		Log.redirectTo(new Log4JLogger());

		// Normal code here
		MBeanServer server = MBeanServerFactory.createMBeanServer();
		...

		// Reset redirection, log in the normal way (to console)
		Log.redirectTo(null);
	}
}
		
		

위의 예제는 또 logging redirection을 어떻게 콘솔에 로그를 표시하는 표준으로 초기화하는지도 보여준다.

새로운 Logger의 프로토타입은 위의 예제에 있는 Log4JLogger를 코드에서나, 시스템 프로퍼티 "mx4j.log.prototype"에 Logger subclass의 FQN(Full Qulified Name)을 설정하면 가능하다. 예를 들면 :

java -Dmx4j.log.prototype=mx4j.log.Log4JLogger MyMainClass

등록된 리스너들에게 notification을 전송하는, MX4J Broadcaster MBean으로 로그를 redirect하는 것이 가능하다. MBeanServer 메카니즘은 이런 notification을 전송할 수 있고, 모든 리스너는 그 자신이 관심없는 것을 제외시키는 필터를 가지고 등록할 수 있다. 아래 예제는 logging 시스템을 broadcaster MBean으로 재전송하는데 필요한 코드를 보여준다.

예 2.8. Broadcaster MBean으로 Logging redirection

		
import mx4j.log.*;

public class Main
{
	public static void main(String[] args) throws Exception
	{
		MBeanServer server = MBeanServerFactory.createMBeanServer();

		// broadcaster logger mbean을 등록
		ObjectName name = new ObjectName("Logger:type=broadcaster");
		server.createMBean("mx4j.log.LoggerBroadcaster", name, null);

		// The filter: 에러들만 logging 되게
		NotificationFilter filter = new NotificationFilter()
		{
			public boolean isNotificationEnabled(Notification notification)
			{
				if (notification.getType().equals("mx4j.logger.error")) {return true;}
				return false;
			}
		};

		// The listener: System.out 대신 System.err로 로깅되게
		NotificationListener listener = new NotificationListener()
		{
			public void handleNotification(Notification notification, Object handback)
			{
				System.err.println("[MX4J ERROR]: " + notification);
			}
		};

		// Register the listener along with the filter
		server.addNotificationListener(name, listener, filter, null);

		// Starts the redirector
		LoggerBroadcasterMBean redirector = (LoggerBroadcasterMBean)MBeanProxy.create(LoggerBroadcasterMBean.class, server, name);
		redirector.start();

		...

		// Stops the redirector
		redirector.stop();
	}
}
		
		

위의 예제는 또 logging redirection을 어떻게 콘솔에 로그를 표시하는 표준 로깅으로 초기화하는지도 보여준다.

MBeanServerInterceptor 설정

MX4J 구현은 MBean 인스턴스를 호출하는 MBeanServer 호출을 위해 사용자정의 인터셉터(interceptor)를 추가하는 클라이언트 코드를 허용한다.

MBeanServer의 MX4J 구현이 생성될 때, MBeanServer-to-MBean 인터셉터 연결을 위한 설정자(configurator)가 생성되고, 이어서 기본 인터셉터들의 세트가 함께 생성된다. (이것들은 클라이언트 코드에 의해서 삭제할 수 없다.)
기본 인터셉터들 각각은 또한 MBean이며, 일반적인 MBean 처럼 모니터링/관리가능하다. 또 설정자도 Mbean이며 ObjectName이 "JMImplementation:type=MBeanServerInterceptorConfigurator"로 등록되어 있다.

인터셉터 설정자는 MBeanServer를 통해서 실행(invoke)될 수 있는 관리용 API를 제공한다.
이 API는 클라이언트 코드에서 사용자 정의 인터셉터를 추가하고 삭제하거나 런타임시에도 logging, performance timing, redirection 등과 같은 추가적인 작업을 수행할 수 있게 한다.

사용자 정의 인터셉터를 작성하는 것은 간단하며, mx4j.server.interceptor.MBeanServerInterceptor 인터페이스를 클라이언트 코드에 구현하거나 mx4j.server.interceptor.DefaultMBeanServerInterceptor 클래스를 상속받도록 한다.

사용자 정의 인터셉터를 작성할 때, MBeanServerInterceptorConfigurator에서 제공하는 아래와 같은 메쏘드를 사용하여 인터셉터 연결(intercepter chain)을 추가할 수 있다.

  • addInterceptor(MBeanServerInterceptor interceptor)
  • registerInterceptor(MBeanServerInterceptor interceptor, ObjectName name)

mx4j.server.interceptor.MBeanServerInterceptorConfigurator 클래스와 이 클래스의 관리 인터페이스는 관련있는 Javadoc API 문서에 자세히 나와있다.
아래는 MBeanServerInterceptorConfigurator API를 사용하는 간단한 예제이다.

예 2.9. 인터셉터 설정자(interceptor configurator) API 사용하기

		
public class Main
{
   public static void main(String[] args) throws Exception
   {
      // MBeanServer 인스턴스 생성
      // 이것은 MBeanServerInterceptorConfigurator MBean의
      // 인스턴스를 생성하고 설정한다.
      MBeanServer server = MBeanServerFactory.createMBeanServer();

      // 설정자의 등록될 이름
      ObjectName name = new ObjectName("JMImplementation:type=MBeanServerInterceptorConfigurator");

      // 사용자 정의 인터셉터 생성
      GetMBeanInfoLoggerInterceptor custom = new GetMBeanInfoLoggerInterceptor();

      // 사용자 정의 인터셉터 설치
      server.invoke(name, "addInterceptor", new Object[] {custom}, new String[] {MBeanServerInterceptor.class.getName()});

      // 이제 getMBeanInfo를 호출할 때마다 logging된다.
      MBeanInfo info = server.getMBeanInfo(name);
   }

   public static class GetMBeanInfoLoggerInterceptor extends DefaultMBeanServerInterceptor
   {
      public MBeanInfo getMBeanInfo(MBeanMetaData metadata)
      {
         // 여러분이 좋아하는 로깅 시스템을 사용하라...
         System.out.println("Call to getMBeanInfo !");
         return super.getMBeanInfo(metadata);
      }
   }
}