Category: Spring 고급편

0

Spring 핵심원리 고급편 - CGLIB

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 참고 https://www.baeldung.com/cglib Dynamic Proxy 의 한계와 CGLIBDynamic Proxy 의 경우 인터페이스를 구현한 클래스에 대해서만 프록시 객체를 생성할 수 있습니다. 그렇다면 인터페이스가 없는 클래스의 경우 프록시 생성을 못하냐? 정답은 아닙니다. 자바에서는 인터페이스를 구현하지 않은 클래스에 대해서도 프록시 객체를 생성할 수 있도록 CGLIB 를 제공합니다. 차이점은 Dynamic Proxy 는 인터페이스 구현을 통해 프록시 객체를 생성하지만 CGLIB 는 상속 을 통해 프록시 객체를 생성한다는 것입니다. CGLIB 란? CGLIB 는 Code Generation Library의 약자로 런타임 시 Java 바이트 코드 를 조작해 동적으로 클래스를 생성하는 라이브러리다. JDK Dynamic 프록시와는 다르게 구체 클래스 만 갖고도 동적으로 Proxy 를 생성할 수 있다. CGLIB은 자바의 리플렉션(Reflection) API 와 바이트코드 조작(Bytecode Manipulation) 기술을 이용하여 클래스의 상속 구조를 이용해서 프록시 객체를 생성합니다. 이 과정에서 바이트코드를 조작하므로, JVM의 클래스 로딩 과정에서 원본 클래스의 바이트코드를 변경할 수 있습니다.

0

Spring 핵심원리 고급편 - Dynamic Proxy 2

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 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; } }} @Configurationpublic class DynamicBasicProxyConfig { @Bean public OrderControllerV1 orderControllerV1(LogTrace logTrace){ OrderControllerV1 orderControllerV1 = new OrderControllerV1Impl(orderServiceV1(logTrace)); // Proxy 객체 생성 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)); // Proxy 객체 생성 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(); // Proxy 객체 생성 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=1005ms2021-11-28 22:18:59.338 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] |<--OrderServiceV1.orderItem() time=1006ms2021-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 한다.

0

Spring 핵심원리 고급편 - Dynamic Proxy 1

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 JDK 동적 프록시 JDK 동적 프록시는 인터페이스 를 기반으로 프록시 를 동적으로 만들어준다.JDK 동적 프록시는 자바 리플렉션(Reflection) 을 이용하여 런타임 시에 인터페이스를 구현하는 프록시 객체 를 생성하는 기술 동적 프록시 기술을 사용하면 개발자가 직접 Proxy 클래스를 생성할 필요가 없이 런타임시 리플랙션의 Proxy 클래스가 동적으로 생성해준다는 장점이 있다. 하지만, 문제가 발생하면 런타임 에러 가 발생하므로 컴파일 시 오류를 찾기가 어려운 문제점 또한 존재한다. 동적 프록시 기술을 사용하면 런타임시 프록시 객체 를 생성해준다. 리플렉션 을 이용해 프록시를 생성한다. 타겟 인터페이스와 동일한 형태로 생성 FactoryBean 을 통해서 생성 프록시 객체는 원본 객체의 대리자 역할을 하며, 클라이언트가 프록시 객체를 통해 원본 객체에 접근하면, 프록시 객체가 요청을 가로채서 필요한 전처리나 후처리를 수행한 후, 최종 결과를 반환합니다. 동적 프록시는 프로그래머가 직접 코드를 작성하지 않아도 인터페이스의 메서드 호출을 가로채서 처리할 수 있어서 매우 유용합니다. 예를 들어, AOP(Aspect Oriented Programming)에서는 동적 프록시를 이용해서 메서드 호출 전후에 로그를 남기거나, 보안 검사를 수행하거나, 트랜잭션 관리를 수행할 수 있습니다. JDK에서는 java.lang.reflect 패키지에서 Proxy 클래스 를 제공합니다. 이 클래스의 정적 메서드인 newProxyInstance() 메서드를 이용하면, 인터페이스와 InvocationHandler 인터페이스를 구현한 클래스를 전달하여 동적 프록시 객체를 생성할 수 있습니다. 이때, InvocationHandler 인터페이스를 구현한 클래스에서는 invoke() 메서드를 구현하여 원본 객체의 메서드 호출을 가로채서 필요한 작업을 수행하도록 구현합니다. newProxyInstance

0

Spring 핵심원리 고급편 - 리플렉션

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 리플렉션 구체적인 클래스 타입을 알지 못해도 해당 클래스의 메소드, 타입, 변수들을 사용할 수 있도록 하는 자바 API 자바 Reflection 은 실행 중인 자바 프로그램 에서 클래스 정보에 접근하도록 하는 기술입니다. Reflection을 사용하면 클래스나 인터페이스의 이름, 필드의 이름, 타입 및 값, 메서드의 이름, 파라미터 타입 등의 정보를 가져오고 조작할 수 있습니다. 이를 통해 객체의 생성, 필드값 설정, 메서드 호출 등을 동적으로 수행할 수 있습니다. 리플렉션 - API클래스 정보 가져오기 - forNameClass 클래스의 forName 메서드를 사용하여 클래스 정보를 가져옵니다. 예를 들어, 다음과 같이 클래스 정보를 가져올 수 있습니다. Class<?> myClass = Class.forName("com.example.MyClass");

0

Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2public class OrderRepositoryConcreteProxy extends OrderRepositoryV2 { private final OrderRepositoryV2 target; private final LogTrace logTrace; public OrderRepositoryConcreteProxy(OrderRepositoryV2 target, LogTrace logTrace) { this.target = target; this.logTrace = logTrace; } @Override public void save(String itemId) { TraceStatus status = null; try{ status = logTrace.begin("OrderRepository.request()"); // target 호출 target.save(itemId); logTrace.end(status); }catch (Exception ex){ logTrace.exception(status, ex); throw ex; } }} public class OrderServiceConcreteProxy extends OrderServiceV2 { private final OrderServiceV2 target; private final LogTrace logTrace; public OrderServiceConcreteProxy(OrderServiceV2 target, LogTrace logTrace) { super(null); this.target = target; this.logTrace = logTrace; } @Override public void orderItem(String itemId) { TraceStatus status = null; try{ status = logTrace.begin("OrderService.orderItem()"); // target 호출 target.orderItem(itemId); logTrace.end(status); }catch (Exception ex){ logTrace.exception(status, ex); throw ex; } }} public class OrderControllerConcreteProxy extends OrderControllerV2 { private final OrderControllerV2 target; private final LogTrace logTrace; public OrderControllerConcreteProxy(OrderControllerV2 target, LogTrace logTrace) { super(null); this.target = target; this.logTrace = logTrace; } @Override public String request(String itemId) { TraceStatus status = null; try{ status = logTrace.begin("OrderController.request()"); // target 호출 String result = target.request(itemId); logTrace.end(status); return result; }catch (Exception ex){ logTrace.exception(status, ex); throw ex; } } @Override public String noLog() { return target.noLog(); }} @Configurationpublic class ConcreteProxyConfig { @Bean public OrderControllerV2 orderControllerV2(LogTrace logTrace){ OrderControllerV2 controllerImpl = new OrderControllerV2(orderServiceV2(logTrace)); return new OrderControllerConcreteProxy(controllerImpl, logTrace); } @Bean public OrderServiceV2 orderServiceV2(LogTrace logTrace){ OrderServiceV2 serviceImpl = new OrderServiceV2(orderRepositoryV2(logTrace)); return new OrderServiceConcreteProxy(serviceImpl, logTrace); } @Bean public OrderRepositoryV2 orderRepositoryV2(LogTrace logTrace){ OrderRepositoryV2 repositoryImpl = new OrderRepositoryV2(); return new OrderRepositoryConcreteProxy(repositoryImpl, logTrace); }} //@Import(AppV1Config.class)//@Import({AppV1Config.class, AppV2Config.class})//@Import(InterfaceProxyConfig.class)@Import(ConcreteProxyConfig.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 14:45:36.692 INFO 98295 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [56d57615] OrderController.request()2021-11-28 14:45:36.693 INFO 98295 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [56d57615] |-->OrderService.orderItem()2021-11-28 14:45:36.693 INFO 98295 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [56d57615] | |-->OrderRepository.request()2021-11-28 14:45:37.696 INFO 98295 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [56d57615] | |<--OrderRepository.request() time=1003ms2021-11-28 14:45:37.696 INFO 98295 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [56d57615] |<--OrderService.orderItem() time=1003ms2021-11-28 14:45:37.697 INFO 98295 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [56d57615] OrderController.request() time=1005ms

0

Spring 핵심원리 고급편 - 구체 클래스 기반 프록시

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시@Slf4jpublic class ConcreteLogic { public String operation(){ log.info("ConcreteLogic 실행"); return "data"; }} public class ConcreteClient { private ConcreteLogic concreteLogic; public ConcreteClient(ConcreteLogic concreteLogic) { this.concreteLogic = concreteLogic; } public void execute(){ concreteLogic.operation(); }} @Testvoid noProxy(){ ConcreteLogic concreteLogic = new ConcreteLogic(); ConcreteClient client = new ConcreteClient(concreteLogic); client.execute();} 구체 클래스 기반 프록시 적용 자바에서 다형성은 인터페이스를 구현하든 상위 클래스를 상속하던 상위 타입만 맞으면 다형성이 적용 된다.

0

Spring 핵심원리 고급편 - 인터페이스 프록시 1

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 @RequiredArgsConstructorpublic class OrderRepositoryInterfaceProxy implements OrderRepositoryV1 { // 실제 객체 참조 private final OrderRepositoryV1 target; private final LogTrace logTrace; @Override public void save(String itemId) { TraceStatus status = null; try{ status = logTrace.begin("OrderRepository.request()"); // target 호출 target.save(itemId); logTrace.end(status); }catch (Exception ex){ logTrace.exception(status, ex); throw ex; } }} @RequiredArgsConstructorpublic class OrderServiceInterfaceProxy implements OrderServiceV1 { private final OrderServiceV1 target; private final LogTrace logTrace; @Override public void orderItem(String itemId) { TraceStatus status = null; try{ status = logTrace.begin("OrderService.orderItem()"); // target 호출 target.orderItem(itemId); logTrace.end(status); }catch (Exception ex){ logTrace.exception(status, ex); throw ex; } }} @RequiredArgsConstructorpublic class OrderControllerInterfaceProxy implements OrderControllerV1 { private final OrderControllerV1 target; private final LogTrace logTrace; @Override public String request(String itemId) { TraceStatus status = null; try{ status = logTrace.begin("OrderController.request()"); // target 호출 String result = target.request(itemId); logTrace.end(status); return result; }catch (Exception ex){ logTrace.exception(status, ex); throw ex; } } @Override public String noLog() { return target.noLog(); }} Proxy Bean 등록@Configurationpublic class InterfaceProxyConfig { @Bean public OrderControllerV1 orderController(LogTrace logTrace){ OrderControllerV1Impl controllerImpl = new OrderControllerV1Impl(orderService(logTrace)); return new OrderControllerInterfaceProxy(controllerImpl, logTrace); } @Bean public OrderServiceV1 orderService(LogTrace logTrace){ OrderServiceV1Impl orderServiceImpl = new OrderServiceV1Impl(orderRepository(logTrace)); return new OrderServiceInterfaceProxy(orderServiceImpl, logTrace); } @Bean public OrderRepositoryV1 orderRepository(LogTrace logTrace){ OrderRepositoryV1 orderRepositoryImpl = new OrderRepositoryV1Impl(); return new OrderRepositoryInterfaceProxy(orderRepositoryImpl, logTrace); }} //@Import(AppV1Config.class)//@Import({AppV1Config.class, AppV2Config.class})@Import(InterfaceProxyConfig.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 13:54:09.793 INFO 97198 --- [nio-8080-exec-2] h.p.trace.logtrace.ThreadLocalLogTrace : [86b4baba] OrderController.request()2021-11-28 13:54:09.795 INFO 97198 --- [nio-8080-exec-2] h.p.trace.logtrace.ThreadLocalLogTrace : [86b4baba] |-->OrderService.orderItem()2021-11-28 13:54:09.795 INFO 97198 --- [nio-8080-exec-2] h.p.trace.logtrace.ThreadLocalLogTrace : [86b4baba] | |-->OrderRepository.request()2021-11-28 13:54:10.798 INFO 97198 --- [nio-8080-exec-2] h.p.trace.logtrace.ThreadLocalLogTrace : [86b4baba] | |<--OrderRepository.request() time=1003ms2021-11-28 13:54:10.798 INFO 97198 --- [nio-8080-exec-2] h.p.trace.logtrace.ThreadLocalLogTrace : [86b4baba] |<--OrderService.orderItem() time=1003ms2021-11-28 13:54:10.798 INFO 97198 --- [nio-8080-exec-2] h.p.trace.logtrace.ThreadLocalLogTrace : [86b4baba] OrderController.request() time=1005ms

0

Spring 핵심원리 고급편 - Decorator Pattern 2

목차 Post not found: springboot/spring-aop/cglib/cglib-01 Post not found: springboot/spring-aop/dynamic-proxy/dynamic-proxy-02 Post not found: springboot/spring-aop/dynamic-proxy/dynamic-proxy-01 Post not found: springboot/spring-aop/dynamic-proxy/reflection Post not found: springboot/spring-aop/concrete-proxy/concrete-proxy-04 Post not found: springboot/spring-aop/concrete-proxy/concrete-proxy-02 Post not found: springboot/spring-aop/concrete-proxy/concrete-proxy-01 Post not found: springboot/spring-aop/decorator/decorator-02 Post not found: springboot/spring-aop/decorator/decorator-01 Post not found: springboot/spring-aop/proxy-pattern/proxy-04 Post not found: springboot/spring-aop/proxy-pattern/proxy-03 Post not found: springboot/spring-aop/proxy-pattern/proxy-02 Post not found: springboot/spring-aop/proxy-pattern/proxy-01 Post not found: springboot/spring-aop/strategy-pattern/strategy-pattern-01 Post not found: springboot/spring-aop/template-method/template-method-01 Spring 핵심원리 고급편 - Decorator Pattern 적용@Slf4jpublic class TimeDecorator implements Component{ private Component component; public TimeDecorator(Component component) { this.component = component; } @Override public String operation() { log.info("TimeDecorator 실행"); long startTime = System.currentTimeMillis(); String result = component.operation(); long endTime = System.currentTimeMillis(); long resultTime = endTime - startTime; log.info("TimeDecorator 종료 resultTime = {}ms", resultTime); return null; }} @Testvoid decorator2(){ Component realComponent = new RealComponent(); Component messageDecorator = new MessageDecorator(realComponent); Component timeDecorator = new TimeDecorator(messageDecorator); DecoratorPatternClient client = new DecoratorPatternClient(timeDecorator); client.execute();} Decoratro Pattern 은 항상 내부에 꾸며 줄 대상(Component) 가 존재해야 한다.

0

Spring 핵심원리 고급편 - Decorator Pattern 1

목차 Post not found: spring/design-pattern/spring-aop/cglib/cglib-01 Post not found: spring/design-pattern/spring-aop/dynamic-proxy/dynamic-proxy-02 Post not found: spring/design-pattern/spring-aop/dynamic-proxy/dynamic-proxy-01 Post not found: spring/design-pattern/spring-aop/dynamic-proxy/reflection Post not found: spring/design-pattern/spring-aop/concrete-proxy/concrete-proxy-04 Post not found: spring/design-pattern/spring-aop/concrete-proxy/concrete-proxy-02 Post not found: spring/design-pattern/spring-aop/concrete-proxy/concrete-proxy-01 Post not found: spring/design-pattern/spring-aop/decorator/decorator-02 Post not found: spring/design-pattern/spring-aop/decorator/decorator-01 Post not found: spring/design-pattern/spring-aop/proxy-pattern/proxy-04 Post not found: spring/design-pattern/spring-aop/proxy-pattern/proxy-03 Post not found: spring/design-pattern/spring-aop/proxy-pattern/proxy-02 Post not found: spring/design-pattern/spring-aop/proxy-pattern/proxy-01 Post not found: spring/design-pattern/spring-aop/strategy-pattern/strategy-pattern-01 Post not found: spring/design-pattern/spring-aop/template-method/template-method-01 Decorator 패턴 Decorator 패턴 은 기존 객체 수정없이 부가 기능 추가 를 위해 주로 사용하는 디자인 패턴이다. Decorator 패턴은 객체 지향 디자인 원칙 중 하나인 개방-폐쇄 원칙(OCP) 을 따릅니다. 이 패턴을 사용하면 코드의 수정 없이 기존 클래스에 새로운 기능을 추가하거나 기존 기능을 수정할 수 있습니다. Decorator 클래스는 기본 객체와 같은 인터페이스를 사용해 구현되며, 기본 객체를 Wrapping 하여 추가적인 기능을 제공합니다. 이러한 구조는 객체 간의 결합도를 낮추고, 유연성과 확장성을 높입니다. 기존 객체를 감싸는 Wrapper 클래스 를 만들고, Wrapper 클래스에 새로운 기능을 추가하는 방식으로 새로운 기능을 추가하거나 기존 기능을 수정하는데 사용됩니다. Decorator 패턴을 사용하면 객체의 기존 동작을 변경하지 않고도 객체에 새로운 동작을 추가할 수 있습니다. Decorator 패턴의 구성요소 Component 인터페이스나 추상 클래스로 정의된 기본 객체의 공통 인터페이스입니다. ConcreteComponent Component 인터페이스를 구현한 실제 객체입니다. Decorator Component 인터페이스를 구현하며, 기본 객체를 래핑하고 추가적인 기능을 제공하는 추상 클래스입니다. ConcreteDecorator Decorator 추상 클래스를 상속받아 기본 객체를 래핑하고 추가적인 기능을 구현한 실제 객체입니다.

0

Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 Spring 핵심원리 고급편 - Proxy Pattern 컴포넌트 스캔으로 자동 빈 등록@Repositorypublic class OrderRepositoryV3 { public void save(String itemId) { if(itemId.equals("ex")){ throw new IllegalStateException("예외 발생!"); } sleep(1000); } private void sleep(int millis) { try { Thread.sleep(millis); }catch (InterruptedException ex){ ex.printStackTrace(); } }} @Servicepublic class OrderServiceV3 { private final OrderRepositoryV3 orderRepository; public OrderServiceV3(OrderRepositoryV3 orderRepository) { this.orderRepository = orderRepository; } public void orderItem(String itemId) { orderRepository.save(itemId); }} @RestController@Slf4jpublic class OrderControllerV3 { private final OrderServiceV3 orderService; public OrderControllerV3(OrderServiceV3 orderService) { this.orderService = orderService; } @GetMapping("/v3/request") public String request(String itemId) { orderService.orderItem(itemId); return "ok"; } @GetMapping("/v3/no-log") public String noLog() { return "ok"; }}

0

Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 Spring 핵심원리 고급편 - Proxy Pattern 인터페이스 없는 없는 구체 클래스Repositorypublic class OrderRepositoryV2 { public void save(String itemId) { if(itemId.equals("ex")){ throw new IllegalStateException("예외 발생!"); } sleep(1000); } private void sleep(int millis) { try { Thread.sleep(millis); }catch (InterruptedException ex){ ex.printStackTrace(); } }} Servicepublic class OrderServiceV2 { private final OrderRepositoryV2 orderRepository; public OrderServiceV2(OrderRepositoryV2 orderRepository) { this.orderRepository = orderRepository; } public void orderItem(String itemId) { orderRepository.save(itemId); }} Controller@Slf4j@RequestMapping@ResponseBodypublic class OrderControllerV2 { private final OrderServiceV2 orderService; public OrderControllerV2(OrderServiceV2 orderService) { this.orderService = orderService; } @GetMapping("/v2/request") public String request(String itemId) { orderService.orderItem(itemId); return "ok"; } @GetMapping("/v2/no-log") public String noLog() { return "ok"; }} Bean 등록

0

Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 Proxy 패턴 기능을 수행하는 실제 객체 대신 가상의 객체(Proxy) 를 생성해 로직의 흐름을 제어 하는 방법 Proxy 는 사전적인 의미로 대리자, 대변인의 의미를 갖고 있다. 프로그램 로직 실행시 실제 객체 대신 Proxy 객체에 로직을 대신 맡기게 된다.(객체의 접근을 제어한다.) 실제 객체 생성을 해당 객체를 사용하기 전 시점까지 미룰 수 있는 장점이 있다.(lazy-loading 가능) RepositoryRepository 인터페이스public interface OrderRepositoryV1 { void save(String itemId);} Repository 구현 클래스public class OrderRepositoryV1Impl implements OrderRepositoryV1{ @Override public void save(String itemId) { if(itemId.equals("ex")){ throw new IllegalStateException("예외 발생!"); } sleep(1000); } private void sleep(int millis) { try { Thread.sleep(millis); }catch (InterruptedException ex){ ex.printStackTrace(); } }}

0

Spring 핵심원리 고급편 - Proxy 패턴

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 Proxy 패턴 - 실제 객체에 대한 접근 제어를 위한 디자인 패턴 기능을 수행하는 실제 (Real) 객체 대신 가상의 (Proxy) 객체 를 이용해 실제 객체 에 대한 접근을 제어 하는 디자인 패턴 프록시 패턴은 객체 지향 프로그래밍에서 사용되는 디자인 패턴 중 하나로 실제 객체와 같은 인터페이스 를 제공하는 객체를 사용하여 실제 객체에 대한 접근을 제어하는 데 사용됩니다. 즉, 프록시 객체를 사용하여 실제 객체에 대한 액세스를 제어할 수 있습니다. 프록시 객체는 실제 객체에 대한 참조를 유지하고, 클라이언트가 실제 객체에 액세스하려고 할 때 대신 실제 객체에 대한 요청을 처리합니다. 프록시 객체는 실제 객체와 같은 인터페이스를 구현하므로, 클라이언트는 프록시 객체와 실제 객체를 동일한 방식으로 사용할 수 있습니다. 프록시 패턴의 사용 사례로는 다음과 같은 것들이 있습니다. 원격 객체에 대한 액세스 원격 객체에 대한 액세스를 제어하려면, 클라이언트는 원격 객체에 직접 액세스하지 않고, 원격 객체를 대신하여 프록시 객체를 사용합니다. 이때 프록시 객체는 원격 객체에 대한 액세스를 제어하고, 원격 객체에 대한 요청을 처리합니다. 보안 프록시 객체를 사용하여 실제 객체에 대한 액세스를 제어하면, 보안상 이점이 있습니다. 프록시 객체를 사용하면, 클라이언트는 실제 객체에 직접 액세스하지 않고, 프록시 객체를 통해 액세스하므로, 실제 객체에 대한 액세스를 제어하고 보안을 유지할 수 있습니다. 비용 실제 객체에 대한 액세스 비용이 높은 경우, 프록시 객체를 사용하여 액세스 비용을 줄일 수 있습니다. 예를 들어, 원격 객체에 대한 액세스는 네트워크 비용이 들기 때문에, 원격 객체에 직접 액세스하는 것보다 프록시 객체를 사용하여 원격 객체에 대한 액세스 비용을 줄일 수 있습니다. 캐싱 프록시 객체를 사용하여 실제 객체에 대한 액세스를 캐싱할 수 있습니다. 이때 프록시 객체는 실제 객체에 대한 요청을 처리하기 전에 캐시된 결과를 반환합니다. 이를 통해, 실제 객체에 대한 액세스 비용을 줄이고, 성능을 향상시킬 수 있습니다. Proxy 패턴의 구성 요소

0

Spring 핵심원리 고급편 - Template Callback 패턴

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 콜백이란 콜백, 콜에프터 함수란 다른 코드의 인수로서 넘겨주는 실행 가능한 코드콜백을 넘겨받는 코드는 이 콜백을 필요에 따라 즉시 실행할 수 있고, 아니면 나중에 실행할 수 있다. public interface Callback { void call();} @Slf4jpublic class TimeLogTemplate { public void execute(Callback callback){ long startTime = System.currentTimeMillis(); // 비즈니스 로직 실행 callback.call(); // 비즈니스 로직 종료 long endTime = System.currentTimeMillis(); long resultTime = endTime - startTime; log.info("resultTime = {}", resultTime); }} Template Callback Pattern 실행직접적으로 Callback 객체내 call 메소드를 실행하는 것이 아닌 TimeLogTemplate 객체에서 execute 메소드를 실행하게 되면 Callback 객체를 넘겨주고 execute 내에서 Callback 객체의 call 메소드가 실행된다. @Slf4jpublic class TemplateCallbackTest { @Test void callbackV1(){ TimeLogTemplate template = new TimeLogTemplate(); template.execute(new Callback() { @Override public void call() { log.info("비즈니스 로직 1 실행"); } }); // 람다식 적용 template.execute(() -> log.info("비즈니스 로직 2 실행")); }}

0

Spring 핵심원리 고급편 - Strategy 패턴

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 Strategy 패턴 Strategy 패턴 은 변하지 않는 부분을 Context 에 두고 변하는 부분을 Strategy 라는 Interface 를 만들고 해당 인터페이스를 구현해 코드 중복성을 해결한다. Strategy 패턴 코드 중복 문제를 해결하기 위한 디자인 패턴 중 하나로 Context 와 Strategy 으로 구성됩니다. 공통 로직은 Context 클래스로 만들어 관리하고 서로 다른 로직들을 Strategy 인터페이스를 구현하는 방식으로 코드 중복 문제를 해결합니다. Strategy 패턴 에서 Context 클래스는 내부에 Strategy 클래스를 가지고 있습니다. 이 구조는 Context 객체가 실행될 때, 내부에 저장된 Strategy 객체를 활용하여 작업을 수행하게 됩니다. 따라서 Context 객체는 실행 시 Strategy 객체에 의존하게 됩니다. Strategy 클래스들은 서로 다른 로직을 가지고 있지만 동일한 인터페이스로 구현됩니다. 결과적으로 Context 클래스는 동일한 메소드 호출을 통해 다양한 Strategy 객체를 실행할 수 있습니다. Template Method 패턴과의 차이점은 공통적인 부분을 추상 클래스에서 관리하고 상속을 통해 변하는 부분을 구현해 코드 중복성을 해결 했습니다. Startegy Pattern 은 상속이 아니라 위임 으로 문제를 해결한다. Strategy 인터페이스 - 변하는 로직을 관리