개발자 준비/Spring AOP

[스프링 AOP 동작 원리] 프록시 (feat.완전한 서브로직 분리)

osul_world 2022. 2. 10. 20:50
728x90

[스프링 AOP 동작 원리] 프록시 (feat.완전한 서브로직 분리)


횡단 관심사

한 애플리케이션 전반에 로그를 남기는 기능은 특정 기능 하나에 관심이 있는 기능이 아니다. 애플리케이션의 여러 기능들 사이에 걸쳐서 들어가는 관심사이다.

이것을 바로 횡단 관심사(cross-cutting concerns)라고 한다.

 

횡단 관심사를 분리해서 하나의 코드로 관리하는 것을 AOP라고 한다.

 

쓰래드 로컬

  • 로그추적기에 관한 자세한 설계는 영상 참고 - 예제 ~ 쓰래드로컬
private ThreadLocal<TraceId> traceIdHolder = new ThreadLocal<>();

LogTrace를 만들때 ThreadLocal 이란 것을 사용한다.

LogTrace ThreadLocalLogTrace의 필드 traceHolder에 TraceId를 유지한다.

이때, 여러 쓰래드가 동시에 traceHolder에 접근하는 경우 서로 영향을 미친다.

 

ThreadLocal을 사용해서 동시성 문제를 해결할수있다.

ThreadLocal을 사용해서 각 쓰래드별로 메모리저장소를 따로 지정해서 사용하도록 할수있다.

쓰래드 풀을 사용하는경우. 반드시 사용후 파기해야한다.

쓰래드가 작업이 끝나고 쓰래드 풀로 복귀했을때 다른 작업을 위해 그 쓰래드가 재할당 될수있다.

이때, ThreadLocal를 파기하지 않았으면 이전 작업내역 메모리를 그대로 사용하기때문에 문제가 발생할수있다.

꼭 작업이 종료되면 해당 쓰래드 풀을 제거하자.

 

프록시를 이용해 완전한 서브로직 분리

로그를 찍기위한 코드를 컨트롤러에 추가한 모습이다.

원래 컨트롤러의 핵심 로직과 로그를 찍기위한 서브 로직이 뒤섞여있는 모습을 볼수있다.

@RestController
@RequiredArgsConstructor
public class OrderControllerV3 {

    private final OrderServiceV3 orderService;
    private final LogTrace trace;

    @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;
        }
    }
}

 

로그를 찍고자하는 모든 곳에 저렇게 로그를 찍는 코드를 추가하면 "코드중복"이 너무 심하다.

 

디자인패턴 템플릿 메서드 패턴이나 전략 패턴을 사용해서 어느정도 "코드중복"을 줄일수있겠지만,

완전한 분리는 불가능하다.

 

변하는 코드와 변하지 않는 코드를 분리하는것은 중요하다.

 

프록시 패턴은?

프록시 패턴을 이용하면 완전한 분리가 가능하다.

프록시 패턴을 이용하면 본 객체를 대신해서 클라이언트의 요청을 받고 본객체를 요청해 동작을 수행한다.

인터페이스 기반, 클래스 기반이 있다.

 

이 과정에서 프록시에 로그를 찍는 서브 코드를 추가하면 본 객체의 핵심로직과 서브로직을 분리 할 수 있다.

 

  • 스프링 빈에는 본 객체 대신 프록시 객체를 대신 저장하면 된다.

 

 

문제점: 본 객체의 수 만큼 프록시 객체를 생성해야한다.

본 객체가 수백개라면 프록시 객체도 수백개가 생성된다.

 

이런 문제를 동적 프록시 를 이용해 해결할 수 있다.

728x90