Spring 핵심원리 고급편 - ProxyFactory 적용

목차

참고

본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다.

인터페이스 객체에 프록시 팩토리 적용

스프링에서 제공하는 MethodInterceptor 인터페이스를 이용해

import org.aopalliance.intercept.MethodInterceptor;

public class LogTraceAdvice implements MethodInterceptor {

private final LogTrace logTrace;

public LogTraceAdvice(LogTrace logTrace) {
this.logTrace = logTrace;
}

@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
TraceStatus status = null;

try {
Method method = invocation.getMethod();
String message = method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()";
status = logTrace.begin(message);

// 로직 호출
Object result = invocation.proceed();

logTrace.end(status);

return result;
} catch (Exception ex) {
logTrace.exception(status, ex);
throw ex;
}
}
}
@Slf4j
@Configuration
public class ProxyFactoryConfigV1 {

@Bean
public OrderControllerV1 orderControllerV1(LogTrace logTrace){
OrderControllerV1 orderController = new OrderControllerV1Impl(orderServiceV1(logTrace));

// OrderControllerV1 객체를 Proxy 객체로 생성한다.
ProxyFactory factory = new ProxyFactory(orderController);
factory.addAdvisor(getAdvisor(logTrace)); // Advisor 를 적용한다.
OrderControllerV1 proxy = (OrderControllerV1) factory.getProxy();

log.info("ProxyFactory proxy = {}, target = {}", proxy.getClass(), orderController);

return proxy;
}

@Bean
public OrderServiceV1 orderServiceV1(LogTrace logTrace){
OrderServiceV1Impl orderService = new OrderServiceV1Impl(orderRepositoryV1(logTrace));

// OrderServiceV1Impl 객체를 Proxy 객체로 생성한다.
ProxyFactory factory = new ProxyFactory(orderService);
factory.addAdvisor(getAdvisor(logTrace)); // Advisor 를 적용한다.
OrderServiceV1 proxy = (OrderServiceV1) factory.getProxy();

log.info("ProxyFactory proxy = {}, target = {}", proxy.getClass(), orderService);

return proxy;
}

@Bean
public OrderRepositoryV1 orderRepositoryV1(LogTrace logTrace){
OrderRepositoryV1Impl orderRepository = new OrderRepositoryV1Impl();

// OrderRepositoryV1Impl 객체를 Proxy 객체로 생성한다.
ProxyFactory factory = new ProxyFactory(orderRepository);
factory.addAdvisor(getAdvisor(logTrace)); // Advisor 를 적용한다.
OrderRepositoryV1 proxy = (OrderRepositoryV1) factory.getProxy();

log.info("ProxyFactory proxy = {}, target = {}", proxy.getClass(), orderRepository);

return proxy;
}

private Advisor getAdvisor(LogTrace logTrace) {
// Point Cut
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("request*", "order*", "save*");

// advice
LogTraceAdvice advice = new LogTraceAdvice(logTrace);

// Pointcut과 Advice 를 이용해 Advisor 객체를 만들어준다.
return new DefaultPointcutAdvisor(pointcut, advice);
}
}

애플리케이션 로딩 시점에서 해당 Bean 이 Loading 되는 것을 확인할 수 있다.

2021-12-05 01:09:21.671  INFO 64531 --- [           main] h.p.c.v.ProxyFactoryConfigV1             : ProxyFactory proxy = class com.sun.proxy.$Proxy50, target = hello.proxy.app.v1.OrderRepositoryV1Impl@5555ffcf
2021-12-05 01:09:21.673 INFO 64531 --- [ main] h.p.c.v.ProxyFactoryConfigV1 : ProxyFactory proxy = class com.sun.proxy.$Proxy52, target = hello.proxy.app.v1.OrderServiceV1Impl@5a2fa51f
2021-12-05 01:09:21.674 INFO 64531 --- [ main] h.p.c.v.ProxyFactoryConfigV1 : ProxyFactory proxy = class com.sun.proxy.$Proxy53, target = hello.proxy.app.v1.OrderControllerV1Impl@6ecdbab8

구체클래스에 프록시 팩토리 적용

구체 클래스에 적용

@Slf4j
@Configuration
public class ProxyFactoryConfigV2 {

@Bean
public OrderControllerV2 orderControllerV2(LogTrace logTrace){
OrderControllerV2 orderController = new OrderControllerV2(orderServiceV2(logTrace));

// OrderControllerV2 객체를 Proxy 객체로 생성
ProxyFactory factory = new ProxyFactory(orderController);
factory.addAdvisor(getAdvisor(logTrace));
OrderControllerV2 proxy = (OrderControllerV2) factory.getProxy();

log.info("ProxyFactory proxy = {}, target = {}", proxy.getClass(), orderController);

return proxy;
}

@Bean
public OrderServiceV2 orderServiceV2(LogTrace logTrace){
OrderServiceV2 orderService = new OrderServiceV2(orderRepositoryV2(logTrace));

// OrderServiceV2 객체를 Proxy 객체로 생성
ProxyFactory factory = new ProxyFactory(orderService);
factory.addAdvisor(getAdvisor(logTrace));
OrderServiceV2 proxy = (OrderServiceV2) factory.getProxy();

log.info("ProxyFactory proxy = {}, target = {}", proxy.getClass(), orderService);

return proxy;
}

@Bean
public OrderRepositoryV2 orderRepositoryV2(LogTrace logTrace){
OrderRepositoryV2 orderRepository = new OrderRepositoryV2();

// OrderRepositoryV2 객체를 Proxy 객체로 생성
ProxyFactory factory = new ProxyFactory(orderRepository);
factory.addAdvisor(getAdvisor(logTrace));
OrderRepositoryV2 proxy = (OrderRepositoryV2) factory.getProxy();
log.info("ProxyFactory proxy = {}, target = {}", proxy.getClass(), orderRepository);

return proxy;
}

private Advisor getAdvisor(LogTrace logTrace) {

// Point Cut
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("request*", "order*", "save*");

// advice
LogTraceAdvice advice = new LogTraceAdvice(logTrace);

// Pointcut 과 Advice 를 이용해 Advisor 객체를 생성한다.
return new DefaultPointcutAdvisor(pointcut, advice);
}
}

CGLIB 로 생성된 것을 확인할 수 있다.

2021-12-05 01:18:11.287  INFO 64747 --- [           main] h.p.c.v.ProxyFactoryConfigV2             : ProxyFactory proxy = class hello.proxy.app.v2.OrderRepositoryV2$$EnhancerBySpringCGLIB$$47389dce, target = hello.proxy.app.v2.OrderRepositoryV2@75961f16
2021-12-05 01:18:11.292 INFO 64747 --- [ main] h.p.c.v.ProxyFactoryConfigV2 : ProxyFactory proxy = class hello.proxy.app.v2.OrderServiceV2$$EnhancerBySpringCGLIB$$9b88cbf1, target = hello.proxy.app.v2.OrderServiceV2@2dd2e270
2021-12-05 01:18:11.295 INFO 64747 --- [ main] h.p.c.v.ProxyFactoryConfigV2 : ProxyFactory proxy = class hello.proxy.app.v2.OrderControllerV2$$EnhancerBySpringCGLIB$$493fc484, target = hello.proxy.app.v2.OrderControllerV2@7d04529c
Share