특수한 목적이 있어 logstash로 임의의 jar파일을 동적으로 load하여 runtime 환경에서 클래스를 불러와 해당 클래스의 메서드를 사용해야 했습니다.
우선 jar파일을 읽어오는 plugin이 공식적으로 존재하지 않기 때문에 custom filter plugin을 작성했습니다. 작성한 plugin은 테스트용으로 만든 jar파일을 잘 읽어들였고, 해당 jar에 포함된 클래스를 생성하여 내부의 메서드를 사용하는 것까지 잘 동작하는 것을 확인하여 배포하였습니다.
그러나 실제 사용환경에서 해당 플러그인을 사용해 jar를 load하려고 했을 때 InvocationTargetException
을 마주쳤습니다. (테스트 다 해보고 배포했는데 외?않?되?😭)
java doc에서는 InvocationTargetException
을 다음과 같이 설명하고 있었습니다.
InvocationTargetException is a checked exception that wraps an exception thrown by an invoked method or constructor.
As of release 1.4, this exception has been retrofitted to conform to the general purpose exception-chaining mechanism. The "target exception" that is provided at construction time and accessed via the getTargetException() method is now known as the cause, and may be accessed via the Throwable.getCause() method, as well as the aforementioned "legacy method."
InvocationTargetException
은 메서드나 생성자를 호출할 때 발생한 예외를 감싸고 있는 예외입니다. 원래의 예외를 얻기 위해서는 getTargetException()
메서드를 사용할 수 있었지만, 이제는 getCause()
메서드를 통해서도 접근할 수 있습니다. 이러한 변경은 예외 체인을 통해 예외의 원인을 추적하고 처리하는 데 도움을 주는 일반적인 예외 처리 방법과 일치하도록 하기 위한 것입니다.
해당 예외가 발생했을 때 printStackTrace()
를 통해 예외를 출력하게 되면 작성한 logstash custom plugin에서 Exception이 발생한 것처럼 스택이 찍히게 되고 왜 문제가 일어났는지 정확한 파악이 어렵습니다.
정확한 디버깅을 위해 메서드를 가져오는 try-catch 구문에 어디서 정확히 어디서 예외가 발생했는지 추적할 수 있게 getTargetException()
을 추가해야 합니다.
try {
// reflection을 통해 메서드를 가져온다.
} catch (InvocationTargetException e) {
e.getTargetException().printStackTrace();
}
예외가 발생한 이유를 추적해보니 메서드를 불러오다가 java.lang.NoClassDefFoundError
가 발생하였습니다. 해당 에러는 실행환경에서 해당 클래스를 찾을 수 없는 경우에 발생하는 에러입니다. reflection을 통해 가져온 메서드 내부에서 java 8까지만 지원하는 클래스를 참조하고 있었습니다. logstash에 java 15를 사용하고 있었기 때문에 jdk버전이 달라 해당 클래스를 찾을 수 없어서 생긴 문제였습니다.
logstash를 jdk8로 실행시켜 문제를 해결했습니다!
oracle doc : https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/InvocationTargetException.html