스프링/스프링 핵심 원리 - 고급편 36

36. JDK 동적 프록시

동적 프록시, 동적으로 프록시를 만들어 주는 것이다. 프록시 객체를 새로 만들어 주는 것 이다. 우리가 프록시 적용해야할 것이 100개 클래스면 100개 다 만들어야 했었는데, 이거는 이제 자동으로 그 클래스에 따라 만들어 주게끔 하는 것이 가능하다. JDK 동적 프록시는 자바에서 공식적으로 지원해 주는 것. 근데 이것은 인터페이스가 필수이다. 프록시로 쓸 로직은 인터페이스에 넣어놔야 한다. public interface AInterface { String call(); } 이렇게 비즈니스 로직용 인터페이스 만들어 주고 @Slf4j public class AImpl implements AInterface{ @Override public String call() { log.info("A 호출"); retu..

35. 리플렉션

리플렉션이란 클래스나 메소드의 메타 정보를 얻을 수 있는 것 이다. @Test void reflection1() throws Exception { Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello"); Hello target = new Hello(); Method methodCallA = classHello.getMethod("callA"); Object result1 = methodCallA.invoke(target); log.info("result1={}", result1); Method methodCallB = classHello.getMethod("callB"); Object result2 = methodCa..

34. 인터페이스 기반 프록시 vs 구체클래스 프록시

사실 다른 클래스 끼리의 관계 자체는 똑같은데, 인터페이스냐 구체클래스냐의 차이인데, 아무래도 인터페이스가 좋긴 하다. 역할과 기능구현이 딱 나뉘니까. 그리고, 구체 클래스 프록시의 단점은. 의미없게 super 생성자 호출해야 한다는 점 final 클래스면 상속 불가 final 메소드면 오버라이드 불가. 인터페이스 기반 프록시의 단점은 인터페이스를 써야 한다는 점. 또 캐스팅 관련해서 단점이 있다고 한다. 이건 나중에.. 이론적으론 역할과 구현을 인터페이스처럼 확실히 나누는 게 좋지만, 바뀔 일 없이 구현체 하나만 만들어도 되는 것이 존재한다. 그래서 둘이 섞여 있으므로, 둘 다 프록시를 만들 수 있어야 한다. 그리고, 지금까지 봐왔단 단점. 기능은 LogTrace 하나인데, 그 공통적인 것을 프록시마다..

32. 구체 클래스에 프록시 적용

당연한 이야기지만, 구체 클래스를 상속받은 자식으로 프록시를 이용할 수 있다. 이미 시스템 다 짜놨는데 나중에 추가적으로 기능 추가하고 싶을 때. @Slf4j public class ConcreteLogic { public String operation(){ log.info("ConcreateLogic 실행"); return "data"; } } 먼저 이런 핵심 로직이 있다고 치고 public class ConcreteClient { private ConcreteLogic concreteLogic; public ConcreteClient(ConcreteLogic concreteLogic) { this.concreteLogic = concreteLogic; } public void execute(){ co..

31. 로그트레이스 프록시 적용

기존에, v1 버전은 애초에 모두 인터페이스로 만들어 뒀었다. public interface OrderRepositoryV1 { void save(String itemId); } 이런 식으로. 이제 이거를 프록시로 새로 만들면 된다. public class OrderServiceV1Impl implements OrderServiceV1{ private final OrderRepositoryV1 orderRepository; public OrderServiceV1Impl(OrderRepositoryV1 orderRepository) { this.orderRepository = orderRepository; } @Override public void orderItem(String itemId) { order..

30. 데코레이터 패턴

public interface Component { String operation(); } 인터페이스 @Slf4j public class RealComponent implements Component{ @Override public String operation() { log.info("RealComponent 실행"); return "data"; } } 실제 서버에서 동작할 로직 @Slf4j public class MessageDecorator implements Component{ private Component component; public MessageDecorator(Component component) { this.component = component; } @Override public S..

29. 프록시 패턴

public interface Subject { String operation(); } 이렇게 먼저 클라이언트 - 서버의 관계라고 치면 서버의 인터페이스를 먼저 만들고, @Slf4j public class RealSubject implements Subject{ @Override public String operation() { log.info("실제 객체 호출"); sleep(1000); return "data"; } private void sleep(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { throw new RuntimeException(e); } } } 서버의 기능 구현. 그냥 대략 1초정도 데이터 가져..

28. 프록시 패턴과 데코레이션 패턴

프록시 직역은 대리자 말 그대로 대리 처리 예를 들어 이런 걸 이렇게. 앞에서 먼저 한번 필요한 걸 처리한 뒤 넘길 수 있다. 이렇게 하면 할 수 있는게 어떤 접근을 보고 차단할 수도 있고, 요청 데이터를 가공한다든지 등 할 수 있다. 이런 것도 가능 그래서, 이걸 클라이언트 로직에 손 댈 필요 없이 하려면, 이렇게 서버를 인터페이스로 둬서 서버로직과, 프록시 서버 로직으로 나눔. 그 후 클라이언트가 인터페이스에 의존하게 만들고 의존성 주입하면 됨. 프록시 패턴은 개념임. 클라이언트 -> 서버 간에도 프록시가 가능하고, 객체 -> 객체 간에도 프록시가 가능함. 저렇게 중간에 대리자가 있으면 크게 2가지 일을 할 수 있는데, 접근 제어 특정 요청에 대한 접근 차단, 캐싱, 지연로딩 부가기능 추가 원래 서버..

27. 프록시, 데코레이션 패턴 예제 틀 및 요구사항

@Slf4j @RestController public 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"; } } @Service public class Order..