이 장의 목적은 MX4J 개발자들에게 시작할 공통적인 기반을 제공하는 몇가지 제안을 제공하는데 있다. 더 나아가, MX4J 새 릴리즈를 만들고 배포하는 공통 지시(indication)을 제공한다.
Java에 대한 코딩 관례는 시작하는 기반이다. 여기를 참고 온라인 괄호 하나 스타일의 추가적인 관례를 필요로 한다 :
예 7.1. One-line one-brace style
public class Main { // bad private String name; public Main(String n) { // bad if (n != null) { // bad name = n; } } } public class Main { // good private String name; public Main(String n) { // good if (n != null) { // good name = n; } } }
코드에 로깅 문을 집어넣는 것은 디버깅을 돕고, 프로그램이 무엇을 하고 있는지에 대한 정보를 기록할 수 있는 좋은 예제가 된다.
MX4J는 사용법이 Log4J project의 Category클래스와 매우 유사한 mx4j.log.Logger클래스에 기반하는 built-in 로깅시스템을 가지고 있다.
Logger 클래스는 다른 priority를 가지는 여섯개의 메소드를 가진다. 낮은 우선순위부터 높은 순위로 :
public void trace
(...);
public void debug
(...);
public void info
(...);
public void warn
(...);
public void error
(...);
public void fatal
(...);
Logger 클래스는 Logger인스턴스에 대한 우선순위 설정을 반환하는 유용한 메소드를 가진다 :
public boolean isEnabledFor
(...);
예 7.2. run-time시 String 연결 비용 줄이기
Logger logger = ...; if (logger.isEnabledFor(Logger.TRACE)) { logger.trace("Result is: " + result + " on item: " + item + " for process: " + process); }
String 객체 생성을 피하는 또 다른 유용한 방법은 아래 예제와 같이 StringBuffer 클래스를 사용하는 것이다 :
예 7.3. StringBuffer를 사용하여 String 연결의 run-time비용 절약하기
Logger logger = ...; if (logger.isEnabledFor(Logger.TRACE)) { StringBuffer message = new StringBuffer("Result is: ").append(result).append(" on item: ").append(" for process: ").append(process); logger.trace(message); }
Logger 클래스의 인스턴스를 어떻게 얻을 수 있을까? mx4j.log.Log를 다음 방법으로 사용하여야 한다.
예 7.4. Logger 인스턴스 가져오기
Logger logger = Log.getLogger("MyCategory");
적절한 우선순위를 선정하는 것은 중요하며, 몇가지 가이드라인이 있다 :
Logger.trace
는 실행 플로우를 log하기위해
사용한다. 항상 Logger.isEnabledFor
를 호출하는 곳 안에 trace 순위의 로그를 남긴다.
Logger.debug
는 변수의 값을 log하기 위해 사용한다.
항상 Logger.isEnabledFor
를 호출하는 곳 안에 trace 순위의 로그를 남긴다.
Logger.info
는 사용자가 관심을 가질 수 있�
정보를 log하는데 사용한다. 모든 public 메소드는 적어도 하나의 info 순위의 log를 가져야 한다.
항상 Logger.isEnabledFor
를 호출하는 곳 안에 trace 순위의 로그를 남긴다.
Logger.warn
는 정상적인 상황에서는 발생해서는
안되는 복구가능한 에러에 대한 로그에 사용한다. warn 순위는 MX4J의 디폴트 순위이다.
Logger.error
는 exception을 로그한다.
일반적으로 error 순위는 catch 블럭안에 log가 있으며, rethrowing 하기전에 사용한다.
예 7.5. error 순위에서의 로그
Logger logger = ...; try { thisMethodThrows(); } catch (Exception x) { logger.error("Exception happened: ", x); throw x; }
Logger.fatal
(...);는 JVM이 종료될 에러를
log하는데 사용되낟. 일반적으로 log는 catch 블럭내에서 사용되며, System.exit
를 호출하기 전에 사용된다.
예 7.6. fatal 순위 로그 사용
Logger logger = ...; try { Class.forName("java.lang.Object"); } catch (ClassNotFoundException x) { logger.fatal("Can't find core classes", x); System.exit(1); }
System.exit
는 절대로
호출되어서는 안된다.
MX4J와 함께 제공되는 문서는 DocBook를 사용하여 작성된다. DocBook을 사용하는 것은 매우 쉽고, 온라인 매뉴얼이 여기 있다
일반적으로, 레이아웃은 index.xml에 정의된다. 다른 파일들은 장에 속하는 DocBook 섹션들이며, index.xml에 정의된다.
모든 섹션은 작성자와 revision history를 에 대한 정보를 가지는 sectioninfo를 호함해야 한다. 문단을 섹션에 추가하는 모든 작성자들은 authors의 리스트에 추가하여야만 하며, tag의 revnumber와 date는 CVS 키워드 $Revision$와 $Date$ 포함하여야 한다. 이렇케 하여 모든 섹션은 CVS에 의해 매 commit시 자동적으로 update될 수 있을 것이며, reader는 즉시 이 문서가 얼마나 되었는지 알 수 있을 것이다.
MX4J를 릴리즈하는 데에는 다음과 같은 절차가 필요하다.
MX4J JMX 에이전트의 기본 구현 클래스는 mx4j.server.MBeanServerImpl이다.
MBeanServer 구현 클래스는 다음의 역할을 수행한다 :
JMX 에이전트에 대한 정보는 getDefaultDomain()
나 mx4j.server.MBeanServerImpl클래스에
직접 구현된 여러가지 메소드를 통해서 제공될 수 있다.
등록된 MBean들은 저장소에 보관된다.
MBeanServer구현은 저장소 작업을 명시한 mx4j.server.MBeanRepository인터페이스의 구현을
위임 수행한다. 따라서, MBeanServer 구현은 MBeanRepository 객체에 대한 factory로서
동작할 수 있다. 하지만, 실제 구현은 MBeanRepository 객체에 위임한다.
MBeanRepository는 시스템 프로퍼티 "mx4j.mbeanserver.repository"에 구현된 클래스의 전체 이름(FQN)을 명시하여
다른 MBeanRepository 구현 클래스로 대체하는 것이 가능하다.
MBean이 등록될 때, MBean의 MBean호환인지 아닌지, MBeanInfo 정보를 가져올 것인지등,
형을 알아내기 위해서 몇가지 체크가 이루어 져야 한다.
MBeanServer 구현은 이런 작업을 mx4j.server.MBeanIntrospector클래스에 위임한다.
이 클래스의 객체는 먼저 주어진 MBean에 대한 완벽한 조사를 요청한다.
MBeanIntrospector가 MBean에 대한 모든 정보를 수집하면, mx4j.server.MBeanMetaData
클래스의 인스턴스가 된고, MBeanServer 구현은 MBeanIntrospector를 통해서 MBean 호환인지를 체크하게 된다.
MBean이 표준 MBean이면, MBean 관리 인터페이스나 MBean invoker를 생성하는데
사용하기 위해서 MBeanIntrospector는 MBeanInfo 정보를 생성해야 한다. 아래를 보자.
MBeanIntrospector의 역할은 이렇케 MBean 호환성을 체크하고, 표준 MBean에 대해 MBeanInfo 정보를 생성하며,
MBean Invoker에 대한 factory로서 동작하는 것이다.
MBeanServer 구현은 사용자 편의를 위해서 등록된 MBean들의 operation invoker로 동작한다.
구조는 가로채기(interceptor)기반이고, 클라이언트에서 호출하면, MBeanServer 메소드는 MBean 인스턴스를 호출하고,
이것이 interceptor 체인에 보내지게 되며, 궁극적으로는 MBean 인스턴스에 전달된다.
The architecture is interceptor-based, that is whenever you call
from a client an MBeanServer method that will end up to call the MBean instance, the call is dispatched to
the interceptor chain and eventually to the MBean instance.
The interceptors are configurable via the MBeanServer Interceptor Configurator MBean, that is an MBean
of class mx4j.server.MBeanServerInterceptorConfigurator registered under the
"JMImplementation" domain.
When the call is about to arrive to the MBean instance, the last interceptor dispatches the call depending on
the MBean type: if the MBean is a dynamic MBean, the call is dispatched directly using the methods of the
DynamicMBean interface; if the MBean is a standard
MBean, then an MBean invoker is delegated to invoke the operation on the MBean instance.
MBean invokers are implementations of the mx4j.server.MBeanInvoker interface.
There are 2 default MBean invoker implementations: the first is based on reflection to invoke the MBean instance,
the second is based on an on-the-fly generated class that invokes the MBean directly.
This on-the-fly generated class is created at registration time; its bytecode is built at runtime using the
Byte Code Engineering Library.
Both versions make use of TernaryTree as fast caches for MBean information, so that the invocations on
standard MBeans are really FAST.
Early performance benchmarks reveal that the on-the-fly generated version is 2 times faster than the one that use
reflection.
자세한 정보는 언급된 클래스에 대한 Javadoc API을 참고하시오.