분류 전체보기
-
프록시 - 프록시 패턴과 데코레이션 패턴이란?스프링/스프링 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..
-
로그 추적기스프링/스프링 AOP 2023. 9. 3. 17:30
로직을 수행할 때 어떤 로직들을 호출하는지, 에러는 어디서 나는지 확인을 하기 위해 로그로 남기는 것을 로그 추적기라고 한다. 로그 추적기는 로그만 출력하는 용도로 사용해야하며 애플리케이션에 영향을 끼치면 안된다. 예를 들어 try-catch문을 사용할 때 로그 추적기에서 예외를 처리하면 안되고, throw e를 통해 예외를 던져야만 한다. 로그에 들어가는 내용은 traceId와 traceStatus이다. traceId는 UUID로 로직을 수행할 때 같은 요청임을 표시해주기 위함이다. traceStatus는 로직의 시간, 메시지, traceId를 전달한다. TraceId @Getter public class TraceId { private String id; private int level; public..
-
fetch join으로 성능 최적화프로젝트/Trend-Pick 2023. 8. 16. 15:41
프로젝트를 시작했을 때에는 JPQL를 간단히만 사용할 수 있었기 때문에 성능 문제에 대해서는 크게 고려를 안하고 값만 받아오는 데에 신경을 썼다. public List findAllPost() { List AllPost = em.createQuery("select p from Post p", Post.class) .getResultList(); return AllPost; } 예를 들어 post를 전부 가져오는 findAllPost()이다. 하지만 컨트롤러에서 post의 member에 접근해서 조회해야하는 상황이 있다. @GetMapping("/post_list") public List postList() { List findPosts = postService.findAllPost(); List post..