SpringPlus- 개인과제(4)

ChoRong0824·2025년 3월 14일
0

Web

목록 보기
40/51
post-thumbnail

과제를 진행하기에 앞서 복습겸 개념에 대해 설명하도록 하겠습니다. ㅎㅎ

AOP

일단, aop 관점지향 프로그래밍은 핵심 비즈니스 로직과 별개로 반복적으로 사용하는 부가기능 (로깅, 트랜잭션 관리, 보안 등)을 별도로 분리하여 코드의 중복을 최소하하는 방법입니다.

<핵심 개념>
Aspect(관점), Advice(보조 로직), JoinPoint(적용 지점), PointCut(적용 범위 지정)


@ASpectdhk Advice 종류

@Aspect와 Advice 종류
@Before → 메서드 실행 전 AOP 실행
@After → 메서드 실행 후 AOP 실행
@Around → 메서드 실행 전, 후 모두 AOP 실행 가능
@AfterReturning → 메서드가 정상적으로 실행된 후 AOP 실행
@AfterThrowing → 예외 발생 시 AOP 실행

JoinPoint와 Pointcut 표현식

Spring AOP에서 Pointcut을 설정할 때 사용할 수 있는 표현식은 ?

@Pointcut("execution(* org.example.expert..*(..))") // 특정 패키지 이하 모든 메서드
@Pointcut("execution(* org.example.expert.domain.user.controller.UserController.getUser(..))") // 특정 메서드
@Pointcut("within(org.example.expert.domain.user.controller..*)") // 특정 패키지 내부 모든 클래스
@Pointcut("bean(*Service)") // 이름이 'Service'로 끝나는 모든 빈에 적용

여기서 더 나아가서 필요한 개념이 있다면 ?
쁘로오오옹ㄱ쒸위위?
이게 뭐야~~~ 라고 할 수 있지만, 간단히 생각하시면 됩니다. 나중엔 프록시 객체 쏼롸쏼라 나오면 그때 더 공부하시면 좋을 것 같습니다.!

프록시

  • Spring AOP는 기본적으로 프록시 기반으로 동작한다.
  • 프록시 방식은 클래스 기반 CGLIB 또는 인터페이스 기반 JDK Dynamic Proxy 방식이 있다.
  • Spring AOP는 기본적으로 JDK Dynamic Proxy 를 사용하지만, 인터페이스가 없으면 CGLIB(바이트코드 조작) 방식을 사용한다.

Spring AOP의 한계

1. 프록시 방식의 한계

private 메서드에는 적용 불가
final 클래스에는 적용 불가 (CGLIB 사용 시)

2. AspectJ와의 차이

Spring AOP는 메서드 실행 시점(joinPoint)만 제어 가능 → AspectJ는 필드 접근, 객체 생성 시점 등도 제어 가능


현재 코드에는 큰 문제점이 있으며, 요구사항에 맞춰 수정해야합니다.
@After → @Before 로 변경하여 메서드 실행 전에 로그가 남도록 수정
UserAdminController의 changeUserRole()을 대상으로 AOP가 적용되도록 Pointcut 수정


package org.example.expert.aop;

import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class AdminAccessLoggingAspect {

    private final HttpServletRequest request;

    @Before("execution(* org.example.expert.domain.user.controller.UserAdminController.changeUserRole(..))")
    public void logBeforeChangeUserRole(JoinPoint joinPoint) {
        String userId = String.valueOf(request.getAttribute("userId"));
        String requestUrl = request.getRequestURI();
        LocalDateTime requestTime = LocalDateTime.now();

        log.info("Admin Access Log - User ID: {}, Request Time: {}, Request URL: {}, Method: {}",
                userId, requestTime, requestUrl, joinPoint.getSignature().getName());
    }
}

1. 추가적으로 고려할 개념들

(1) AOP의 실행 흐름과 내부 동작

AOP는 Spring 내부에서 프록시를 통해 메서드 실행을 가로채고(advice 적용), 이후 원래 메서드를 실행하는 방식으로 동작한다.
이때 프록시가 생성되는 방식(JDK Dynamic Proxy vs CGLIB)과 AOP 적용 범위를 이해하면, 보다 안정적인 코드 설계가 가능하다.

📌 추가 학습
Spring AOP는 기본적으로 JDK Dynamic Proxy 를 사용하므로 인터페이스가 있는 클래스에만 AOP 적용 가능
인터페이스가 없을 경우 CGLIB 기반의 바이트코드 조작 방식으로 AOP 적용

(2) Spring AOP vs AspectJ 비교

Spring AOP: 런타임 기반, 프록시 방식 → 상대적으로 성능이 좋고 관리가 쉬움
AspectJ: 컴파일 타임 기반, 더 강력한 기능 제공 (필드 접근, 객체 생성 시점 등)

📌 이해가 필요한 부분
Spring AOP의 한계: 메서드 실행 단계에서만 Advice를 적용할 수 있음
AspectJ를 사용해야 하는 경우: 필드 접근 시 로깅, 객체 생성 시 인터셉트 등

현재 요구사항에서는 Spring AOP로 충분하지만, 더 복잡한 AOP 적용이 필요하다면 AspectJ까지 고려할 필요가 있다.

(3) AOP 적용 시 부작용 및 트러블슈팅

AOP가 적용되지 않는 경우

@Component, @Aspect 가 붙어 있지 않음
Spring AOP는 내부(private) 메서드에는 적용되지 않음
AOP 적용 대상이 final class 또는 private 메서드 일 경우 프록시 생성 불가

AOP가 예상과 다르게 동작하는 경우

AOP 내부에서 this 호출 시 Advice가 적용되지 않는 문제
프록시 방식의 특성 때문에 같은 클래스 내의 메서드를 호출할 경우 AOP 적용되지 않음
해결 방법: ApplicationContext에서 해당 빈을 직접 주입받아 호출하면 AOP 적용 가능

@Component
public class MyService {
    @Autowired
    private ApplicationContext applicationContext;

    public void outerMethod() {
        applicationContext.getBean(MyService.class).innerMethod(); // AOP 적용됨
    }

    @Transactional
    public void innerMethod() {
        System.out.println("AOP 적용 메서드 실행");
    }
}

(4) AOP 성능 고려 및 최적화

AOP는 프록시 객체를 생성하고 이를 통해 메서드 호출을 가로채기 때문에 성능 오버헤드가 발생할 수 있다.
많은 트래픽을 처리하는 서비스라면 AOP의 성능 영향을 고려해야 한다.

성능 최적화 방법

Pointcut을 최소한으로 설정 (불필요한 클래스/메서드에 적용하지 않도록)
복잡한 로직을 AOP 내부에서 실행하지 않도록 주의 (@Around 사용 시 부하 주의)
AspectJ 대신 Spring AOP 사용 (AspectJ는 강력하지만 성능 오버헤드 있음)
AOP 적용 범위를 명확하게 지정하여 불필요한 Proxy 생성을 방지


3. 추가 학습 추천 자료

📌 Spring AOP 공식 문서

Spring AOP 공식 문서 📖
🔗 https://docs.spring.io/spring-framework/reference/core/aop.html

📌 블로그 및 실무 예제

Spring AOP의 개념과 실전 활용

🔗 https://jojoldu.tistory.com/139

Spring AOP 적용 시 주의할 점

🔗 https://woowabros.github.io/experience/2020/06/22/spring-aop.html

프록시 기반 AOP와 성능 최적화

🔗 https://velog.io/@devjunu/Spring-AOP와-Proxy


4.추가로 공부하면 좋은 개념 (실무 기준)

📌 1. AOP 적용 대상 심화 학습

AOP는 Spring 프록시 기반으로 동작 → this 키워드를 사용한 내부 메서드 호출은 AOP가 적용되지 않음
해결법: ApplicationContext에서 빈을 직접 가져와 호출

📌 2. AOP와 트랜잭션 (@Transactional) 충돌 문제

AOP와 트랜잭션이 함께 동작할 때 발생할 수 있는 문제
@Transactional 메서드를 AOP에서 감싸는 경우 트랜잭션이 예상과 다르게 커밋될 가능성 있음
해결법: AOP와 트랜잭션 적용 순서를 조정하거나, 필요한 경우 AspectJ를 고려

📌 3. Spring AOP vs AspectJ

AspectJ는 AOP보다 더 강력한 기능 제공 (필드 접근, 객체 생성 감지 가능)
하지만 런타임 성능 오버헤드가 크므로, 일반적인 Spring AOP로 해결 가능한 경우가 많음

📌 4. Spring Boot 3.x에서 AOP 관련 변경 사항

Spring Boot 3.x 이후, @Around를 사용할 때 Spring Proxy 방식이 조금 더 개선됨
Spring 6.x부터 AOP 내부에서 네이티브 이미지와의 호환성이 더 강화됨 (Native Spring 활용 가능)

profile
백엔드를 지향하며, 컴퓨터공학과를 졸업한 취준생입니다. 많이 부족하지만 열심히 노력해서 실력을 갈고 닦겠습니다. 부족하고 틀린 부분이 있을 수도 있지만 이쁘게 봐주시면 감사하겠습니다. 틀린 부분은 댓글 남겨주시면 제가 따로 학습 및 자료를 찾아봐서 제 것으로 만들도록 하겠습니다. 귀중한 시간 방문해주셔서 감사합니다.

0개의 댓글