AOP (Aspect Oriented Programming)

?�� ?�습 코드: com.aop.step1 ~ com.aop.step4
IoC/DI처럼 ?�수 ?�바 ??Spring AOP까�? ?�계?�으�??�습


0. ?�습 ?�름 (Step 1 ??4)

Step ?�키지 ?�심 ?�행
Step 1 com.aop.step1 AOP ?�이 - 부가 로직???�심 로직??직접 ?�임 step1.Main ?�행
Step 2 com.aop.step2 ?�록???�턴 - ?�동?�로 부가 로직 분리 step2.Main ?�행
Step 3 com.aop.step3 JDK Dynamic Proxy - 리플?�션?�로 ?�동 ?�록?? step3.Main ?�행
Step 4 com.aop.step4 Spring AOP - @Aspect + Pointcut ?�언???�용 step4.Main ?�행
Step1: 모든 메서?�에 로깅 코드 중복   ??"?�거 ?�무 불편?�데?"
Step2: ?�록???�턴?�로 분리           ??"분리?��?�??�록???�래?��? 직접 ?�성?�야 ?�네..."
Step3: Dynamic Proxy�??�동??       ??"?�나??Handler�??�결! 근데 Pointcut??불편..."
Step4: Spring AOP�??�전 ?�동??      ??"?�언�??�면 Spring?????�줌!"

1. AOP?�?

?�심 로직(비즈?�스) �?부가 로직(공통 관?�사) ??분리?�는 ?�로그래�?방식.

부가 로직 ?�시:
- 로깅 (메서???�행 ?�간 측정)
- ?�랜??�� (@Transactional???��??�으�?AOP)
- ?�증/?��? 체크
- ?�외 처리

문제 ?�황

// ??AOP ?�이 - 모든 ?�비?�에 로깅 코드가 중복
public class CommunityService {
    public CommunityDTO getCommunityDetail(Long id) {
        long start = System.currentTimeMillis();
        log.info("getCommunityDetail ?�작");
        // ... ?�심 로직
        log.info("getCommunityDetail 종료: {}ms", System.currentTimeMillis() - start);
    }
}

public class FileService {
    public FileEntity getFileById(Long id) {
        long start = System.currentTimeMillis();
        log.info("getFileById ?�작");
        // ... ?�심 로직
        log.info("getFileById 종료: {}ms", System.currentTimeMillis() - start);
    }
}

AOP�??�결

// ??AOP - 로깅 코드�???곳에�??�성
@Aspect
@Component
@Slf4j
public class LoggingAspect {

    // Service 계층??모든 메서?�에 ?�용
    @Around("execution(* com.ch.basic..*Service.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().getName();

        log.info("{} ?�작", methodName);
        Object result = joinPoint.proceed(); // ?�제 메서???�행
        log.info("{} 종료: {}ms", methodName, System.currentTimeMillis() - start);

        return result;
    }
}

2. ?�심 ?�어

?�어 ?�명 ?�시
Aspect 부가 로직??모아???�래?? LoggingAspect
Advice ?�제 부가 로직 (?�제 ?�행?��?) @Before, @After, @Around
Pointcut ?�디???�용?��? ?�현?? execution(* *Service.*(..))
JoinPoint ?�용 가?�한 지?? 메서???�행 ?�점
Target 부가 로직???�용?�는 ?�제 객체 CommunityService
Proxy Target??감싸??AOP 객체 Spring???�동 ?�성

3. Advice 종류

@Aspect
@Component
public class ExampleAspect {

    // 메서???�행 ??
    @Before("execution(* com.ch.basic..*Service.*(..))")
    public void before(JoinPoint joinPoint) {
        log.info("메서???�행 ?? {}", joinPoint.getSignature().getName());
    }

    // 메서???�행 ??(?�외 ?��??�이)
    @After("execution(* com.ch.basic..*Service.*(..))")
    public void after(JoinPoint joinPoint) {
        log.info("메서???�행 ??);
    }

    // ?�상 반환 ??
    @AfterReturning(pointcut = "execution(* com.ch.basic..*Service.*(..))",
                    returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        log.info("? 반환: {}", result);
    }

    // ?�외 발생 ??
    @AfterThrowing(pointcut = "execution(* com.ch.basic..*Service.*(..))",
                   throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex) {
        log.error("? 발생: {}", ex.getMessage());
    }

    // ????모두 ?�어 (가??많이 ?�)
    @Around("execution(* com.ch.basic..*Service.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // ?�행 ??
        Object result = joinPoint.proceed(); // ?�제 메서???�행
        // ?�행 ??
        return result;
    }
}

4. Pointcut ?�현??

execution(?�근?�어??반환?�???�키지.?�래??메서???�라미터))

execution(* com.ch.basic..*Service.*(..))
           ??          ??          ????
           모든 반환   ..(?�위 ?�키지 ?�함)  모든 메서?? 모든 ?�라미터
?�턴 ?�명
* 모든 �?
.. 0�??�상???�키지/?�라미터
execution(* *..*Service.*(..)) ?�름??Service�??�나??모든 ?�래?�의 모든 메서??
@annotation(Transactional) @Transactional 붙�? 메서??

5. ?�무 ?�용 ?�시

// ?�행 ?�간 측정
@Around("execution(* com.ch.basic..*Service.*(..))")
public Object logTime(ProceedingJoinPoint pjp) throws Throwable { ... }

// 로그??체크 (Interceptor?� ?�사)
@Before("execution(* com.ch.basic..*.write(..))")
public void checkLogin(JoinPoint jp) { ... }

// ?�라미터 로깅
@Before("execution(* com.ch.basic..*Controller.*(..))")
public void logRequest(JoinPoint jp) {
    log.info("?�청: {} - ?�라미터: {}", jp.getSignature(), jp.getArgs());
}

6. @Transactional??AOP??

CommunityService.createCommunity() ?�출
    ??
?�제로는 Spring??만든 Proxy 객체가 먼�? 받음
    ??
Proxy: ?�랜??�� ?�작
    ??
?�제 CommunityService.createCommunity() ?�행
    ??
Proxy: ?�공 ??커밋 / ?�외 ??롤백

7. ?�습 코드 ?�세 (Step 1 ??4)

Step 1: AOP ?�이 (com.aop.step1)

?�일 구조:
  step1/
  ?��??� Main.java              ???�행
  ?��??� OrderService.java      ???�심 로직 + 부가 로직 ?�여?�음
  ?��??� OrderRepository.java   ???�이???�근

*?�심 ?�인??: OrderService??모든 메서?�에 로깅/?�간측정 코드가 중복??

// ??모든 메서?�에 같�? 코드가 반복!
public String getOrder(Long id) {
    long start = System.currentTimeMillis();        // 중복
    System.out.println("[LOG] getOrder() ?�작");     // 중복
    String result = orderRepository.findById(id);   // ???�심 로직?� ?�것�?
    long end = System.currentTimeMillis();           // 중복
    System.out.println("[LOG] getOrder() 종료");     // 중복
    return result;
}

Step 2: ?�록???�턴 (com.aop.step2)

?�일 구조:
  step2/
  ?��??� Main.java                ???�행
  ?��??� OrderService.java        ???�터?�이??(?�록???�턴???�심)
  ?��??� OrderServiceImpl.java    ???�심 로직�? (부가 로직 ?�음)
  ?��??� OrderServiceProxy.java   ????부가 로직???�당?�는 ?�록??
  ?��??� OrderRepository.java     ???�이???�근

*?�심 ?�인??: 부가 로직??Proxy�?분리, ?�심 로직?� 깨끗?�짐

Client ??OrderServiceProxy(부가 로직) ??OrderServiceImpl(?�심 로직)
// ???�록?��? 부가 로직???�당
public class OrderServiceProxy implements OrderService {
    private final OrderService target;   // ?�제 객체

    public String getOrder(Long id) {
        // 부가 로직
        String result = target.getOrder(id);   // ?�심 로직 ?�임
        // 부가 로직
        return result;
    }
}

?��? 문제: 메서?�마???�록??코드 ?�성, Service마다 Proxy ?�래???�요


Step 3: JDK Dynamic Proxy (com.aop.step3)

?�일 구조:
  step3/
  ?��??� Main.java                 ???�행
  ?��??� OrderService.java         ???�터?�이??
  ?��??� OrderServiceImpl.java     ???�심 로직
  ?��??� PaymentService.java       ????번째 ?�터?�이??(?�사?�성 증명)
  ?��??� PaymentServiceImpl.java   ???�심 로직
  ?��??� LoggingHandler.java       ????InvocationHandler (?�나�?모든 Service???�용!)
  ?��??� OrderRepository.java      ???�이???�근

*?�심 ?�인??: ?�나??LoggingHandler�??�떤 ?�터?�이?�든 ?�록???�동 ?�성

// ??모든 메서???�출?????�나??메서?�로 ?�어??
public class LoggingHandler implements InvocationHandler {
    private final Object target;

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 부가 로직 (?�행 ??
        Object result = method.invoke(target, args);   // = Spring??proceed()
        // 부가 로직 (?�행 ??
        return result;
    }
}

// ?�용: Proxy.newProxyInstance()�??�적 ?�록???�성
OrderService proxy = (OrderService) Proxy.newProxyInstance(
    OrderService.class.getClassLoader(),
    new Class[]{OrderService.class},
    new LoggingHandler(realService)
);

?��? 문제: ?�터?�이???�수, Pointcut(?�떤 메서?�에 ?�용?��?) 지??불편


Step 4: Spring AOP (com.aop.step4)

?�일 구조:
  step4/
  ?��??� Main.java                 ???�행 (Spring 컨테?�너 ?�용)
  ?��??� AopConfig.java            ??@Configuration + @EnableAspectJAutoProxy
  ?��??� LoggingAspect.java        ????@Aspect - 부가 로직 (?�언??)
  ?��??� OrderService.java         ???�터?�이??
  ?��??� OrderServiceImpl.java     ??@Service - ?�심 로직
  ?��??� PaymentService.java       ???�터?�이??
  ?��??� PaymentServiceImpl.java   ??@Service - ?�심 로직
  ?��??� OrderRepository.java      ???�이???�근

*?�심 ?�인??: @Aspect + Pointcut?�로 ?�언??AOP, Spring???�록???�동 ?�성

@Aspect
@Component
public class LoggingAspect {

    // Pointcut?�로 ?�용 ?�?�을 ?�확??지??
    @Around("execution(* com.aop.step4.*ServiceImpl.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        // 부가 로직 (?�행 ??
        Object result = joinPoint.proceed();   // = Step3??method.invoke()
        // 부가 로직 (?�행 ??
        return result;
    }
}

8. ?�체 비교 ?�리

?��??�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??
?? Step    ?? 방식                    ?? ?�징                        ??
?��??�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??
?? Step 1  ?? AOP ?�음               ?? 부가 로직 직접 ?�성 (중복)  ??
?? Step 2  ?? ?�록???�턴 (?�동)     ?? 분리 ?�공, ?�록??직접 ?�성 ??
?? Step 3  ?? JDK Dynamic Proxy      ?? ?�동 ?�록?? ?�터?�이???�수??
?? Step 4  ?? Spring AOP (@Aspect)   ?? ?�언?? Pointcut, ?�동 ?�록?�│
?��??�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??
?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??
?? Step3 (Dynamic Proxy)        ?? Step4 (Spring AOP)             ??
?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??
?? Proxy.newProxyInstance()     ?? Spring???�동 ?�성             ??
?? InvocationHandler.invoke()   ?? @Around 메서??                ??
?? method.invoke(target, args)  ?? joinPoint.proceed()            ??
?? 모든 메서??무조�??�용      ?? Pointcut?�로 ?�택 ?�용         ??
?? ?�터?�이???�수              ?? ?�래?�만 ?�어??OK (CGLIB)     ??
?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??