전체 글

전체 글

    [Spring] AOP에 대해 (8)

    AOP에 대해 (8) 이번에는 프록시 방식의 AOP가 야기하는 문제점을 살펴보겠다. 내부 호출 문제 앞서 정리한 것을 토대로 우리는 다음과 같이 프록시가 동작한다는 것을 알 수가 있었다. client -> proxy -> target 호출의 순서로 말이다. 그렇다면 다음과 같은 코드는 어떨까? @Slf4j @Component public class CallServiceV0 { public void external() { log.info("call external"); internal(); } public void internal() { log.info("call internal"); } } @Slf4j @Aspect public class CallLogAspect { @Before("execution(*..

    [Spring] AOP에 대해 (7)

    AOP에 대해 (7) 포인트컷 지시자의 종류는 다음과 같다. execution: 메서드 실행 조인 포인트를 매칭 within: 특정 타입 내의 조인 포인트를 매칭 args: 인자가 주어진 타입의 인스턴스인 조인 포인트 this: 스프링 빈 객체(스프링 AOP 프록시)를 대상으로 하는 조인 포인트 target: Target 객체(스프링 AOP 프록시가 가르키는 실제 대상)를 대상으로 하는 조인 포인트 @target: 실행 객체의 클래스에 주어진 타입의 어노테이션이 있는 조인 포인트 @within: 주어진 어노테이션이 있는 타입 내 조인 포인트 @annotation: 메서드가 주어진 어노테이션을 가지고 있는 조인 포인트를 매칭 @args: 전달된 실제 인수의 런타임 타입이 주어진 타입의 어노테이션을 갖는 조..

    [Spring] AOP에 대해 (6)

    AOP에 대해 (6) 애플리케이션 로직은 크게 핵심 기능과 부가 기능으로 나눌 수 있다. 앞서 적용했던 LogTrace가 부가 기능이고 다른 비즈니스 코드들이 바로 핵심 기능이라고 볼 수 있다. 앞에서 겪어봤듯이, 이런 부가 기능을 여러 곳에 적용하기에는 너무 번거롭기 때문에 부가 기능을 핵심 기능에서 분리하고 한 곳에서 관리하도록 했다. 그리고 부가 기능을 어디에 적용할지 선택하는 기능을 만들었다. 부가 기능과 어디에 적용할지 선택하는 기능을 합해서 하나의 모듈로 만들었고 이것이 바로 Aspect다. 앞서 @Aspect로 사용을 해보았다. 스프링이 제공하는 Advisor 도 Advice(부가 기능)과 Pointcut(적용 대상)을 가지고 있어서 개념상 하나의 Aspect다. Aspect를 사용한 프로그..

    [Spring] AOP에 대해 (5)

    AOP에 대해 (5) Advice를 이용해서 V1, V2 코드들을 변경했었으나, V3과 같이 컴포넌트 스캔을 이용한 자동 빈 등록의 경우를 해결하지 못했었다. 이번에는 BeanPostProcessor, 빈 후처리기를 이용해서 해결을 해보려고 한다. 먼저, 일반적인 스프링 빈 등록은 객체를 생성 후에 스프링 컨테이너 내부의 빈 저장소에 등록을 하는 방식이다. 빈 후처리기는 객체 생성 후 빈 저장소에 등록하기 전에 다른 무언가의 처리를 해줄 수가 있다. 위의 3번 작업에서 A객체를 다른 객체로 변환시킨다던가 하는 작업 또한 가능하다. @Slf4j public class BeanPostProcessorTest { @Test public void beanPostProcessor() { AnnotationConf..

    [Spring] AOP에 대해 (4)

    AOP에 대해 (4) Pointcut: 부가 기능 적용 여부를 판단하는 필터링 로직, 주로 클래스와 메서드 이름으로 필터링 한다. 이름 그대로 어떤 포인트(point)에 기능을 적용할지 말지에 대해 잘라서(cut) 구분하는 것이다. Advice: 프록시가 호출하는 부가 기능, 프록시 로직이다. Advisor: Pointcut 1개 + Advice 1개 조언(Advice)를 어디(Pointcut)에 할 것인가? 조언자(Advisor)는 어디(Pointcut)에 조언(Advice)을 해야할지 알고 있다. 코드를 통해 바로 살펴보겠다. 이번에는 save()와 find() 두 메서드를 가지고 있는 인터페이스와 클래스를 이용해보겠다. public interface ServiceInterface { void sav..

    [Spring] AOP에 대해 (3)

    AOP에 대해 (3) 프록시를 이용해서 로그 추적기를 적용했었다. 이 과정에서 많은 프록시 클래스들이 생성됐었다. 이번에는 동적 프록시를 이용해서 프록시 클래스를 계속해서 생성하지 않게끔 해보겠다. 동적 프록시를 이용하면 개발자가 프록시 클래스를 직접 만들어줄 필요가 없게 된다. 이름 그대로 동적으로 런타임에 개발자 대신 만들어준다. JDK 동적 프록시는 인터페이스를 기반으로 프록시를 동적으로 만들어주기 때문에, 인터페이스가 필수적이다. JDK 동적 프록시에 적용할 로직은 InvocationHandler 인터페이스를 구현해서 작성하면 된다. 파라미터로는 프록시 자신, 호출한 메서드, 메서드를 호출할 때 전달한 인수들 이다. 사용법은 아래 코드와 같다. 리플렉션을 이용하게 되는데, 별도의 설명은 생략하겠다..

    [Spring] AOP에 대해 (2)

    AOP에 대해 (2) 템플릿 콜백 패턴을 이용해서 로그 추적기를 적용했었다. 이번에는 프록시 패턴을 이용해서 원본 코드에 손대지 않고 로그 추적기를 적용해보도록 하겠다. 3가지의 각기 다른 버전의 예를 가지고 진행하겠다. 인터페이스를 구현하고, 수동으로 빈 등록 인터페이스 없는 구체 클래스, 수동으로 빈 등록 인터페이스 없는 구체 클래스, 컴포넌트 스캔을 이용하여 빈 등록 다음과 같은 형태이며, V3는 일반적으로 사용하는 @Controller, @Service,@Repository를 이용한 클래스다. V2는 위의 어노테이션만 빠진 상태이고, AppV2Config에서 빈을 등록해주고 있다. @Configuration public class AppV2Config { @Bean public BepozContr..

    [Spring] AOP에 대해 (1)

    AOP에 대해 (1) @RestController @RequiredArgsConstructor public class BepozController { private final BepozService bepozService; @GetMapping("/request") public String request(String itemId) { bepozService.save(itemId); return "ok"; } } @Service @RequiredArgsConstructor public class BepozService { private final BepozRepository bepozRepository; public void save(String id) { bepozRepository.save(id); }..