JAVA

프록시 패턴과 AOP

euicheol0910 2025. 5. 26. 06:24

1. 프록시 패턴 (Proxy Pattern)

  • 정의:
    프록시 패턴은 어떤 객체에 대한 접근을 제어하기 위해, 그 객체를 대신하는 ‘대리인(Proxy)’ 객체를 두는 디자인 패턴입니다.
  • 역할:
    실제 객체에 접근하기 전에 추가 작업(예: 접근 제어, 캐싱, 로깅, 지연 초기화 등)을 수행합니다.
  • 예시:
    • 원격 객체에 대한 접근을 대리하는 원격 프록시
    • 접근 권한 검사를 하는 보호 프록시
    • 무거운 객체를 필요할 때만 생성하는 지연 로딩 프록시 등

 

프록시 패턴의 장점

 

장점  설명
접근 제어 객체에 대한 접근을 제어할 수 있습니다. (예: 권한 검사)
부가기능 추가 원본 객체의 기능에 부가적인 기능을 추가할 수 있습니다. (예: 로깅, 캐싱 등)
지연 초기화 실제 객체를 나중에 생성하여 성능을 최적화할 수 있습니다. (예: 무거운 객체 로딩 시점 지연)

 

 

프록시 패턴 예시 (수동 구현)

 

 

인터페이스와 실제 서비스

public interface UserService {
    void saveUser(String username);
}

public class UserServiceImpl implements UserService {
    @Override
    public void saveUser(String username) {
        System.out.println(username + "님 저장 완료!");
    }
}

 

  • UserService는 핵심 기능(회원 저장)을 위한 인터페이스.
  • UserServiceImpl은 그 실제 구현체로, saveUser가 호출되면 저장 완료 메시지를 출력합니다.

 

프록시 클래스

 

public class UserServiceProxy implements UserService {

    private final UserService target;

    public UserServiceProxy(UserService target) {
        this.target = target;
    }

    @Override
    public void saveUser(String username) {
        System.out.println("[트랜잭션 시작]");  // 부가 기능(트랜잭션 시작)
        target.saveUser(username);               // 실제 핵심 기능 호출
        System.out.println("[트랜잭션 커밋]");  // 부가 기능(트랜잭션 커밋)
    }
}

 

  • UserServiceProxy는 핵심 기능을 호출하기 전후에 부가 기능(여기선 트랜잭션 관리)을 추가하는 역할을 해요.
  • 핵심 객체(UserServiceImpl)를 target으로 받아서 saveUser 호출 시 앞뒤로 로그를 찍습니다.
  • 클라이언트는 이 프록시 객체를 통해 기능을 호출하면, 핵심 기능 + 부가 기능이 같이 실행됩니다.

 

실행부

public class Main {
    public static void main(String[] args) {
        UserService realService = new UserServiceImpl();
        UserService proxy = new UserServiceProxy(realService);

        proxy.saveUser("홍길동");
    }
}

 

  • UserServiceImpl 객체를 직접 쓰지 않고, 프록시(UserServiceProxy)를 생성해 사용합니다.
  • 호출 시 부가 기능과 핵심 기능이 함께 동작합니다.

 

 

실행결과 

[트랜잭션 시작]
홍길동님 저장 완료!
[트랜잭션 커밋]

 

 

2. AOP (Aspect-Oriented Programming)

  • 정의:
    AOP는 핵심 비즈니스 로직과는 별개로, 공통 관심사(cross-cutting concerns) — 예를 들어, 로깅, 트랜잭션 관리, 보안 검사 등을 모듈화해서 코드 중복 없이 재사용할 수 있도록 하는 프로그래밍 패러다임입니다.
  • 핵심 개념:
    • Aspect (관점): 공통 관심사 모듈
    • Advice: 공통 관심사가 실제로 실행되는 코드 (예: Before, After, Around)
    • Join point: Advice가 적용될 수 있는 지점 (예: 메서드 호출)
    • Pointcut: Advice가 적용될 Join point 집합
    • Weaving: Advice를 핵심 코드에 적용하는 과정

 

AOP 없는 코드

 

public class UserService {
    public void createUser() {
        System.out.println("[Log] 사용자 생성 시작"); // 로깅 코드
        // 회원가입 로직
        System.out.println("회원가입 완료");
        System.out.println("[Log] 사용자 생성 끝"); // 로깅 코드
    }
}

 

  • createUser() 안에 비즈니스 로직 + 로깅 로직이 섞임
  • 이걸 여러 메서드마다 반복하면 코드가 지저분해지고 중복이 많아집니다.

 

AOP를 사용한 코드 (Spring)

 

1. 핵심 로직

@Service
public class UserService {
    public void createUser() {
        System.out.println("회원가입 로직 실행");
    }
}

 

 

  • @Service: 이 클래스를 서비스 레이어의 컴포넌트로 등록해주는 Spring 어노테이션입니다.
  • createUser() 메서드에는 오직 핵심 기능만 있습니다.
  • 로깅 등 공통 기능은 따로 Aspect에서 처리됩니다. 이것이 AOP의 핵심입니다.

 

2. 공통 기능: 로깅 Aspect

 

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore() {
        System.out.println("[AOP] 메서드 실행 전 로그");
    }

    @After("execution(* com.example.service.*.*(..))")
    public void logAfter() {
        System.out.println("[AOP] 메서드 실행 후 로그");
    }
}

 

 

코드  의미
@Aspect 이 클래스가 AOP의 Aspect(관심사 모듈) 임을 나타냅니다.
@Component Spring이 이 클래스를 빈으로 자동 등록하게 합니다.
@Before(...) 지정된 메서드 실행 전에 수행할 공통 로직 (Advice)입니다.
@After(...) 지정된 메서드 실행 후에 수행할 공통 로직입니다.
execution(* com.example.service.*.*(..)) com.example.service 패키지 아래의 모든 메서드에 적용하는 Pointcut 표현식입니다.

 

실행결과

 

[AOP] 메서드 실행 전 로그
회원가입 로직 실행
[AOP] 메서드 실행 후 로그

 

 

왜 사용하는가?

  • 관심사 분리 (Separation of Concerns)
  • 코드 중복 제거
  • 유지보수 편리
  • 비즈니스 로직 간결화

'JAVA' 카테고리의 다른 글

SpringBoot VS Spring  (1) 2025.06.16
POJO  (4) 2025.05.21
JAVA 깊은 복제와 얕은 복제  (1) 2025.04.28
JAVA 어노테이션  (0) 2025.04.28
자바의 제네릭에 대하여  (3) 2025.04.23