스프링/스프링 AOP
-
데코레이터 패턴스프링/스프링 AOP 2023. 9. 10. 16:53
데코레이터 패턴은 프록시를 사용하는 디자인 패턴 중에서 부가 기능을 추가시켜주는 패턴이다. Component 인터페이스 public interface Component { String operation(); } Component의 구현체인 RealCcomponent @Slf4j public class RealComponent implements Component { @Override public String operation() { log.info("RealComponent 실행"); return "data"; } } client 계층 - DecoratorPatternClient @Slf4j public class DecoratorPatternClient { private Component compone..
-
프록시 패턴스프링/스프링 AOP 2023. 9. 10. 15:56
프록시를 사용하는 디자인 패턴 중 하나인 프록시 패턴은 접근 제어의 목적을 가지고 있는 패턴이다. 프록시 패턴 도입 전 Subject 인터페이스 public interface Subject { String operation(); } Subject 인터페이스의 구현체인 RealSubject @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)..
-
프록시 - 프록시 패턴과 데코레이션 패턴이란?스프링/스프링 AOP 2023. 9. 10. 15:02
이전의 디자인 패턴들은 로그 추적기를 이용할 때 원본 코드를 어쩔 수 없이 조금이라도 수정했었다. 코드가 많아지면 원본 코드를 수정하기 복잡하기에 원본 코드를 전혀 수정하지 않고 로그 추적기를 도입하려 한다. 프록시(Proxy)라는 개념을 이해하면 이 문제를 해결할 수 있다. 클라이언트와 서버 개념에서 일반적으로 클라이언트가 서버를 직접 호출하고, 처리 결과를 직접 받는게 보통이다. 위의 사진처럼 클라이언트가 서버에 직접 요청하는 것이 아니라, Proxy에 간접 호출을 하는 것이다. 클라이언트 -> Proxy를 참조, Proxy -> Server를 참조 대체 가능 (프록시는 실제 서버처럼 동작할 수 있어야 함) 객체에서 프록시가 되기 위해서는 클라이언트가 요청을 할 때, 서버에 하는 것인지 프록시에 요청..
-
템플릿 콜백 패턴 - 템플릿 패턴, 전략 패턴의 최종스프링/스프링 AOP 2023. 9. 5. 17:45
콜백의 정의 프로그래밍에서 콜백 또는 콜애프터 함수는 다른 코드의 인수로서 넘겨주는 실행 가능한 코드를 말한다. 코드가 호출이 되기는 하지만 코드를 넘겨준 곳의 뒤에서 실행된다는 뜻이다. 이전의 전략패턴에서 예시를 들면 클라이언트에게 직접 Strategy를 실행하는 것이 아니라, 클라이언트가 ContextV2.execute()를 실행할 때 Strategy를 넘겨주고, Context2 뒤에서 Strategy가 실행되는 것이다. 템플릿 콜백 패턴은 GOF 패턴은 아니고, 스프링 내부에서 이런 방식을 자주 사용하기에 스프링에서만 있는 패턴이다. Callback 인터페이스 public interface Callback { void call(); } Callback 인터페이스의 구현체인 TimeLogTemplat..
-
템플릿 패턴의 한계와 전략 패턴스프링/스프링 AOP 2023. 9. 5. 17:10
템플릿 패턴은 부모 클래스가 바뀌면 그것을 의존하고 있는 자식 클래스도 다 바뀌어야 한다는 단점이 있다. 또한, 자식 클래스가 부모 클래스를 알고있어야 하기 때문에 객체지향 관점에서 좋지 않다 전략 패턴 이러한 문제점을 해결하기 위해서 전략 패턴이라는 설계 패턴이 있다. 전략 패턴은 변하지 않는 부분을 Context에 두고 변하는 부분을 Strategy라는 인터페이스를 선언한 다음 해당 인터페이스를 구현하는 방식이다. 전략 패턴은 인터페이스에만 의존하기 때문에 구현체를 바꿔주더라도 큰 문제점이 없다. Strategy 인터페이스 public interface Strategy { void call(); } StrategyLogic1 @Slf4j public class StrategyLogic1 impleme..
-
템플릿 메서드 패턴스프링/스프링 AOP 2023. 9. 3. 23:38
@GetMapping("v3/request") public String request(String itemId) { TraceStatus status = null; try { status = trace.begin("OrderController.request()"); orderService.orderItem(itemId); // 핵심 로직 trace.end(status); return "ok"; } catch (Exception e) { trace.exception(status, e); throw e; } } 원래는 로직이 orderService.orderItem(itemId) 하나뿐인데 로그 추적기를 위해서 코드가 너무 복잡해졌다. 또한, Service와 Repository 계층에서도 같은 코드가 계속해..
-
쓰레드로컬(ThreadLocal) - 동시성 문제의 해결스프링/스프링 AOP 2023. 9. 3. 20:44
쓰레드 로컬을 사용하면 각 쓰레드마다 별도의 내부 저장소를 제공한다. 따라서 같은 인스턴스의 쓰레드 로컬 필드에 접근해도 문제가 없다. thread-A가 userA라는 값을 저장하면 쓰레드 로컬은 thread-A 전용 보관소에 데이터를 넣고, thread-B가 userB라는 값을 저장하면 thread-B의 전용 보관소에 데이터를 넣는 것이다. 자바에서 진행하는 'java.lang.ThreadLocal' 클래스를 잘 사용하면 동시성 문제를 해결할 수 있다. @Slf4j public class ThreadLocalService { private ThreadLocal nameStore = new ThreadLocal(); public String logic(String name) { log.info("저장 n..
-
로그 추적기 필드 동기화 - 동시성 문제 발생스프링/스프링 AOP 2023. 9. 3. 20:12
이전 게시글에 로그 추적기를 만들어서 로그를 출력했다. 트랜잭션 ID와 level을 동기화하기 위해서 traceId를 파라미터로 넘기도록 구현했었는데 동기화는 되었지만 로그를 출력하는 모든 메서드에 traceId 파라미터를 추가해야하는 문제가 있었다. LogTrace 인터페이스 public interface LogTrace { TraceStatus begin(String message); void end(TraceStatus status); void exception(TraceStatus status, Exception e); } FieldLogTrace 구현체 @Slf4j public class FieldLogTrace implements LogTrace{ private static final Stri..