본문 바로가기

Study

JDK Dynamic Proxy

프록시를 관리할 떄 직접 target클래스를 상속받은 클래스를 만들 수 있으나

 

만약 만들어야할 프록시 클래스가 매우 많다면 마찬가지고 중복코드가 가득한 클래스가 많이 만들어지게 된다.

 

어차피 동일한 로직이 수행되는 프록시라면 Java의 Reflection을 이용해서 프록시를 동적으로 생성할 수 있다.

 

Java에서 제공하는 동적 프록시를 이용해서 만들 수 있는데

 

JDK Dynamic Proxy는 인터페이스 기반으로 프록시 클래스를 만들어 준다.

 

 

java.lang.reflect.InvocationHandler

인터페이스를 상속받아 클래스를 구현해서 invoke 부분을 작성하면 해당 프록시가 적용된 모든 인터페이스 기반 프록시에 invoke가 동작하게 된다.

 

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

@Slf4j
public class LogTraceBasicHandler implements InvocationHandler {

	// 실제 수행할 타켓 클래스
    private final Object target;

    public LogTraceBasicHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            // proxy 조건 처리

			// 실제 클래스의 메소드 동작
            Object result = method.invoke(target, args);;

            return result;
        } catch (Exception e) {
            throw e;
        }
    }
}

 

프록시에 동작할 부분을 구현했으면 프록시 클래스를 생성하면 되는데

 

package hello.proxy.config.v2_dynamicproxy;

import hello.proxy.app.v1.*;
import hello.proxy.config.v2_dynamicproxy.handler.LogTraceBasicHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Proxy;

@Configuration
public class DynamicProxyBasicConfig {

    @Bean
    public OrderRepositoryV1 orderRepositoryV1() {
        OrderRepositoryV1 orderRepository = new OrderRepositoryV1Impl();
        OrderRepositoryV1 proxy = (OrderRepositoryV1) Proxy.newProxyInstance(orderRepository.getClass().getClassLoader(),
                new Class[]{OrderRepositoryV1.class},
                new LogTraceBasicHandler(orderRepository));
        return proxy;
    }

}

 

 

중요한 부분은

 

Proxy.newProxyInstance(

                orderRepository.getClass().getClassLoader(),
                new Class[]{OrderRepositoryV1.class},
                new LogTraceBasicHandler(orderRepository)

);

 

로 첫번째 인자에 타겟클래스의 클래스로더를 주입

두번째 인자에 new Class[]{인터페이스.class}

세번째 인자에 작성한 프록시에 대한 InvocationHandler의 구현체를 넣어주면 된다.

'Study' 카테고리의 다른 글

Proxy Factory  (0) 2022.10.05
Cglib dynamic proxy  (0) 2022.10.05
인터페이스 기반 vs 구체 클래스 기반 프록시  (0) 2022.09.29
프록시 패턴 & 데코레이터 패턴  (0) 2022.09.22
프록시  (0) 2022.09.21