목차
public class LogTraceBasicHandler implements InvocationHandler { private final Object target; private final LogTrace logTrace; public LogTraceBasicHandler (Object target, LogTrace logTrace) { this .target = target; this .logTrace = logTrace; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { TraceStatus status = null ; try { String message = method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()" ; status = logTrace.begin(message); method.invoke(target, args); logTrace.end(status); return result; } catch (Exception ex) { logTrace.exception(status, ex); throw ex; } } }
@Configuration public class DynamicBasicProxyConfig { @Bean public OrderControllerV1 orderControllerV1 (LogTrace logTrace) { OrderControllerV1 orderControllerV1 = new OrderControllerV1Impl (orderServiceV1(logTrace)); OrderControllerV1 proxy = (OrderControllerV1) Proxy .newProxyInstance( OrderControllerV1.class.getClassLoader(), new Class []{OrderControllerV1.class}, new LogTraceBasicHandler (orderControllerV1, logTrace)); return proxy; } @Bean public OrderServiceV1 orderServiceV1 (LogTrace logTrace) { OrderServiceV1 orderServiceV1 = new OrderServiceV1Impl (orderRepositoryV1(logTrace)); OrderServiceV1 proxy = (OrderServiceV1) Proxy .newProxyInstance( OrderServiceV1.class.getClassLoader(), new Class []{OrderServiceV1.class}, new LogTraceBasicHandler (orderServiceV1, logTrace)); return proxy; } @Bean public OrderRepositoryV1 orderRepositoryV1 (LogTrace logTrace) { OrderRepositoryV1 orderRepository = new OrderRepositoryV1Impl (); OrderRepositoryV1 proxy = (OrderRepositoryV1) Proxy .newProxyInstance( OrderRepositoryV1.class.getClassLoader(), new Class []{OrderRepositoryV1.class}, new LogTraceBasicHandler (orderRepository, logTrace)); return proxy; } }
@Import(DynamicBasicProxyConfig.class) @SpringBootApplication(scanBasePackages = "hello.proxy.app") public class ProxyApplication { public static void main (String[] args) { SpringApplication.run(ProxyApplication.class, args); } @Bean public LogTrace logTrace () { return new ThreadLocalLogTrace (); } }
2021-11-28 22:18:58.331 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] OrderControllerV1.request() 2021-11-28 22:18:58.333 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] |-->OrderServiceV1.orderItem() 2021-11-28 22:18:58.333 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] | |-->OrderRepositoryV1.save() 2021-11-28 22:18:59.338 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] | |<--OrderRepositoryV1.save() time=1005ms 2021-11-28 22:18:59.338 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] |<--OrderServiceV1.orderItem() time=1006ms 2021-11-28 22:18:59.339 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] OrderControllerV1.request() time=1007ms
특정 메소드에만 부가기능 로직 적용 PatternMatchUtils.simpleMatch 를 사용해 메소드 이름이 조건을 만족하는지 Pattern Matching 한다.
pattern
: pattern 과 정확히 매칭되면 참
pattern*
: pattern 으로 시작하면 참
*pattern
: pattern 으로 끝나면 참
*pattern*
: pattern 이 있으면 참
public class LogTraceFilterHandler implements InvocationHandler { private final Object target; private final LogTrace logTrace; private final String[] patterns; public LogTraceFilterHandler (Object target, LogTrace logTrace, String[] patterns) { this .target = target; this .logTrace = logTrace; this .patterns = patterns; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (!PatternMatchUtils.simpleMatch(patterns, methodName)){ return method.invoke(target, args); } TraceStatus status = null ; try { String message = method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()" ; status = logTrace.begin(message); Object result = method.invoke(target, args); logTrace.end(status); return result; } catch (Exception ex) { logTrace.exception(status, ex); throw ex; } } }
public class DynamicProxyFilterConfig { private static final String[] PATTERNS = {"request*" , "order*" , "save*" }; @Bean public OrderControllerV1 orderControllerV1 (LogTrace logTrace) { OrderControllerV1 orderControllerV1 = new OrderControllerV1Impl (orderServiceV1(logTrace)); OrderControllerV1 proxy = (OrderControllerV1) Proxy.newProxyInstance(OrderControllerV1.class.getClassLoader(), new Class []{OrderControllerV1.class}, new LogTraceFilterHandler (orderControllerV1, logTrace, PATTERNS)); return proxy; } @Bean public OrderServiceV1 orderServiceV1 (LogTrace logTrace) { OrderServiceV1 orderServiceV1 = new OrderServiceV1Impl (orderRepositoryV1(logTrace)); OrderServiceV1 proxy = (OrderServiceV1) Proxy.newProxyInstance(OrderServiceV1.class.getClassLoader(), new Class []{OrderServiceV1.class}, new LogTraceFilterHandler (orderServiceV1, logTrace, PATTERNS)); return proxy; } @Bean public OrderRepositoryV1 orderRepositoryV1 (LogTrace logTrace) { OrderRepositoryV1 orderRepository = new OrderRepositoryV1Impl (); OrderRepositoryV1 proxy = (OrderRepositoryV1) Proxy.newProxyInstance(OrderRepositoryV1.class.getClassLoader(), new Class []{OrderRepositoryV1.class}, new LogTraceFilterHandler (orderRepository, logTrace, PATTERNS)); return proxy; } }
@Import(DynamicProxyFilterConfig.class) @SpringBootApplication(scanBasePackages = "hello.proxy.app") public class ProxyApplication { public static void main (String[] args) { SpringApplication.run(ProxyApplication.class, args); } @Bean public LogTrace logTrace () { return new ThreadLocalLogTrace (); } }