Proxy pattern Spring AOP

이강희·2022년 8월 28일
0
post-thumbnail

Proxy pattern Spring AOP

  1. Proxy pattern이란?
    1. Proxy는 대신이라는 의미이며 다른 무언가와 이어지는 인터페이스의 역할을 하는 패턴입니다. 한마디로 무언가를 대신해주는 대리자입니다.
    2. 풀어서 말하자면 본래 Proxy라는 객체가 해야될 일을 RealSubject 객체에 의존성 주입 시킴으로써 메서드 실행에 대한 책임을 RealSubject에 넘겨주고, Proxy 라는 객체는 외부에게 메서드를 노출하지 않고, 해당 로직대로 흐름을 제어할 수 있습니다.
  2. 프록시 패턴을 왜 사용하고 프록시 객체는 왜 숨는 것일까?
    1. 프록시 패턴은 실제 세계와 비교해서 보면 이해하기 쉽다. 우리가 결제를 할 때 체크카드 (Proxy) 를 사용하여 결제하면 체크카드와 연관되어 있는 은행계좌 (RealSubject)에 돈이 빠져 나가게 된다.
    2. 이때, 역할을 살펴보자면 순전히 결제를 담당하는 것은 Proxy, 은행계좌는 철저하게 외부로부터 숨길 수 있게 된다.
  3. 사용법

1 ) 인터페이스

public interface Payment {
    void cashPay(int amount);
    void creditPay(int amount);
}

2 ) RealSubject

@Service
public class PaymentService implements Payment{

    @Override
    public void cashPay(int amount) {
        System.out.println("cashPay : " + amount);
    }

    @Override
    public void creditPay(int amount) {
        System.out.println("creditPay : " + amount);
    }
}

3 ) Proxy

@Primary // client에 payment를 호출하면 ProxyPaymentService가 먼저 호출된다.
@Service
public class ProxyPaymentService implements Payment {

    @Autowired
    PaymentService paymentService;

    @Override
    public void cashPay(int amount) {
        long begin = System.currentTimeMillis();  // 기능 1
        paymentService.cashPay(1000); // 원래 객체에 위임
        System.out.println(System.currentTimeMillis() - begin); // 기능 2
    }

    @Override
    public void creditPay(int amount) {
        long begin = System.currentTimeMillis();  // 기능 1
        paymentService.creditPay(1000); // 원래 객체에 위임
        System.out.println(System.currentTimeMillis() - begin); // 기능 2
    }
}
  1. AOP

AOP란 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 한다. 여기서 Aspect(관점)이란 흩어진 관심사들을 하나로 모듈화 한 것을 의미한다.

객체 지항 프로그래밍(OOP)에서는 주요 관심사에 따라 클래스를 분할한다. 이 클래스들은 보통 SRP(Single Responsibility Principle)에 따라 하나의 책임만을 갖게 설계된다. 하지만 클래스를 설계하다보면 로깅, 보안, 트랜잭션 등 여러 클래스에서 공통적으로 사용하는 부가 기능들이 생긴다. 이들은 주요 비즈니스 로직은 아니지만, 반복적으로 여러 곳에서 쓰이는 데 이를 흩어진 관심사(Cross Cutting Concerns)라고 한다.

  1. 위와 같이 사용하면 프록시 객체에 중복코드가 발생할 수 있고, 매번 같은 코딩을 해주어야하는 번거러움이 있다. 그래서 스프링 AOP에서는 편리한 기능을 제공한다.
@Component
@Aspect
@EnableAspectJAutoProxy
public class BasicAspect {

    @Around("* basic.PaymentService")
    public Object logPref(ProceedingJoinPoint pjp) throws Throwable {
        long begin = System.currentTimeMillis();
        Object proceed = pjp.proceed();
        System.out.println(System.currentTimeMillis() - begin);
        return proceed;
	    }
}

Around → pointcut으로 클라이언트의 호출을 가로채서 비즈니스 메소드 호출에 책임을 감당한다. 그 때 around Advice 메소드가 비즈니스 메소드의 정보를 가지고 있어야 하는데 그것을 ProceedingJoinPoint 객체라고 한다.

  1. 어노테이션 적용
@Documented
@Target(ElementType.METHOD) // target -> method
@Retention(RetentionPolicy.CLASS) // .class 파일까지 유지
@Retention(RetentionPolicy.SOURCE) // 컴파일 시 사라짐
public @interface PerfLogging {
}
@Component
@Aspect
@EnableAspectJAutoProxy
public class BasicAspect {

    @Around("@annotation(PerfLogging")
    public Object logPref(ProceedingJoinPoint pjp) throws Throwable {
        long begin = System.currentTimeMillis();
        Object proceed = pjp.proceed();
        System.out.println(System.currentTimeMillis() - begin);
        return proceed;
    }
}

김영한님의 스프링 고급 AOP → 정리글

Spring에서 지원하는 AOP Proxy ( CGLIB , JDK Dynamic Proxy ) → 정리글

profile
도전하는 개발자 이강희입니다.

0개의 댓글