[java] Java Byte Buddy를 사용한 메서드 인터셉팅

Java에서는 Byte Buddy 와 같은 라이브러리를 사용하여 메서드 인터셉팅을 구현할 수 있습니다. 이 기술을 사용하면 프로그램의 실행 중에 메서드 호출을 가로채고, 호출 전후에 추가적인 로직을 수행할 수 있습니다. 이는 AOP (Aspect-Oriented Programming) 개념에 기반한 기술로, 코드의 깔끔성과 재사용성을 높일 수 있습니다.

Byte Buddy란?

Byte Buddy는 Java 언어의 상위 수준 API로, 리플렉션(Reflection)과 런타임 프록시(Runtime Proxy)와 같은 자바 언어가 제공하는 기능 이상의 기능을 제공합니다. Byte Buddy는 코드 생성 및 클래스 변경을 쉽게 할 수 있도록 도와줍니다. Byte Buddy는 클래스나 메서드에 대한 어드바이스(Runtime Advice)를 추가하거나 변경할 수 있습니다.

Byte Buddy로 메서드 인터셉팅 구현하기

Byte Buddy를 사용하여 메서드 인터셉팅을 구현하려면 다음 단계를 따르면 됩니다.

  1. Maven이나 Gradle과 같은 의존성 관리 도구를 사용하여 Byte Buddy를 프로젝트에 추가합니다.
<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <version>1.11.5</version>
</dependency>
  1. InterceptHandler 클래스를 작성합니다. 이 클래스는 인터셉팅된 메서드 호출 전후에 실행될 로직을 정의합니다.
public class InterceptHandler {

    public static void before(Object instance, Method method, Object[] args) {
        // 메서드 호출 전에 실행될 로직 작성
    }
    
    public static void after(Object instance, Method method, Object[] args, Object result) {
        // 메서드 호출 후에 실행될 로직 작성
    }
    
}
  1. 인터셉팅을 원하는 클래스에서 메서드 인터셉터를 생성하고 원본 객체와 InterceptHandler를 사용하여 인터셉팅 로직을 추가합니다.
public class ExampleClass {

    public void exampleMethod() {
        // 메서드 인터셉팅을 원하는 로직 작성
    }
    
    public static void main(String[] args) {
        ExampleClass example = new ExampleClass();

        ExampleClass proxy = new ByteBuddy()
                .subclass(ExampleClass.class)
                .method(ElementMatchers.named("exampleMethod"))
                .intercept(MethodDelegation.to(new Interceptor(example)))
                .make()
                .load(ExampleClass.class.getClassLoader())
                .getLoaded();

        proxy.exampleMethod();
    }
    
    public static class Interceptor {
        private Object instance;

        public Interceptor(Object instance) {
            this.instance = instance;
        }

        public void intercept(@This Object obj, @Origin Method method, @AllArguments Object[] args) {
            InterceptHandler.before(instance, method, args);

            // 원본 메서드 호출
            method.invoke(instance, args);

            InterceptHandler.after(instance, method, args, null);
        }
    }
    
}

상기 예제 코드는 Byte Buddy를 사용하여 ExampleClass의 exampleMethod()를 인터셉팅하는 방법을 보여주고 있습니다. Byte Buddy를 사용하여 ExampleClass의 프록시 객체를 생성하고, 해당 프록시 객체를 통해 exampleMethod()를 호출하면, 인터셉터(Interceptor)의 intercept() 메서드가 호출됩니다. intercept() 메서드에서는 InterceptHandler를 이용하여 메서드 호출 전후에 실행될 로직을 수행합니다.

결론

Byte Buddy는 Java 메서드 인터셉팅을 구현하는 강력하고 유연한 도구입니다. Byte Buddy를 사용하면 프로그램의 실행 중에 메서드 호출을 가로채고 추가적인 로직을 수행할 수 있으며, 이는 코드의 깔끔성과 재사용성을 높이는 데 도움이 됩니다.

참고자료: