2025.02.22 (토) - AOP

ChoRong0824·2025년 2월 24일
0

Web

목록 보기
33/51
post-thumbnail

1. AOP 개념 정리

AOP는 핵심 비즈니스 로직과 부가적인 기능(로깅, 트랜잭션, 보안 등)을 분리하여 코드의 가독성을 높이고 유지보수를 용이하게 하는 프로그래밍 기법이며, Spring AOP를 사용하면 메서드 실행 전후, 예외 발생 시 특정 로직을 실행하는 Aspect(관점)을 적용할 수 있습니다.

2. 어노테이션을 활용한 AOP 구현 방법

Spring AOP를 이용하면 @Aspect와 어노테이션을 활용하여 라이브러리(공통 기능)를 인터페이스나 특정 로직에 적용할 수 있습니다.

  1. 어노테이션 정의

    • 메서드에 적용할 커스텀 어노테이션을 만듦
    @Target(ElementType.METHOD) // 메서드에만 적용
    @Retention(RetentionPolicy.RUNTIME) // 런타임 시점까지 유지
    public @interface LogExecutionTime {
    }
  2. AOP설정 및 Aspect 클래스 구현
    - @Aspect를 사용하여 특정 어노테이션이 붙은 메서드의 실행 시간을 측정하는 기능을 추가

    
    @Aspect
    @Component
    public class LoggingAspect {
    
      @Around("@annotation(com.example.annotation.LogExecutionTime)")
      public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
          long start = System.currentTimeMillis();
    
          Object proceed = joinPoint.proceed(); // 실제 메서드 실행
    
          long executionTime = System.currentTimeMillis() - start;
          System.out.println(joinPoint.getSignature() + " 실행 시간: " + executionTime + "ms");
    
          return proceed;
      }
    }
  3. AOP 적용
    - 어노테이션 사용 특정 메서드에 @LogExecutionTime 어노테이션을 붙이면 실행 시간이 자동으로 로그에 찍힙니다.

    
    @Service
    public class UserService {
    
      @LogExecutionTime
      public void getUsers() {
          try {
              Thread.sleep(500); // 0.5초 대기
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          System.out.println("유저 목록 조회 완료");
      }
    }
  1. 실행 결과
execution(UserService.getUsers()) 실행 시간: 501ms
유저 목록 조회 완료

라이브러리화 및 인터페이스 적용

AOP 기능을 라이브러리로 만들어서 공통 모듈로 활용할 수도 있습니다.
이를 위해 별도의 JAR 파일로 만들어 다른 프로젝트에서도 적용할 수 있습니다.

인터페이스 적용 (공통 로직 적용)

특정 인터페이스를 구현하는 모든 클래스에서 AOP를 적용하려면 아래와 같이 설정할 수 있습니다.

@Around("execution(* com.example.service.UserServiceImpl.*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
    /**
    * AOP 기능 유지
    */ 
}

또는 특정 인터페이스인 UserService를 구현한 모든 클래스에 적용하려면
@Around("execution(* com.example.service.UserService+.*(..))") 이렇게 +를 붙이면, UserService를 구현한 모든 클래스에 적용되게 된느 것입니다.


AOP 활용

스프링 AOP를 활용하면 특정 메소드에 어노테이션을 붙여 해당 메소드 호출 시 자동으로 로깅 등의 공통 관심사를 적용할 수 있습니다. Gradle 의존성을 추가하고, 커스텀 어노테이션과 Aspect 클래스를 작성하는 방식으로 구현할 수 있습니다.

1. Gradle 의존성 추가

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-aop'
}

만약 Spring Boot가 아닌 일반 스프링 프로젝트라면, AspectJ 관련 라이브러리와 스프링 AOP 의존성을 별도로 추가해야 합니다.

2, 커스텀 어노테이션 작성

로그를 남길 위치에 붙일 커스텀 어노테이션을 생성합니다. 예를 들어, @LogExecution이라는 어노테이션을 다음과 같이 작성할 수 있습니다

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecution {
}

이 어노테이션은 런타임까지 유지되며, 메소드에 붙여서 로깅을 적용할 수 있습니다.

3. Aspect 클래스 작성

이제 실제 AOP 로직을 담은 Aspect 클래스를 작성합니다. Aspect 클래스에서는 어노테이션이 붙은 메소드를 포인트컷으로 지정하고, 해당 메소드의 실행 전후에 로깅을 수행하도록 구현합니다.

@Aspect
@Component
public class LoggingAspect {

    @Around("@annotation(com.example.LogExecution)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        // 메소드 실행 전 시간 기록
        long start = System.currentTimeMillis();
        
        // 실제 대상 메소드 실행
        Object proceed = joinPoint.proceed();
        
        // 메소드 실행 후 경과 시간 계산
        long executionTime = System.currentTimeMillis() - start;
        
        // 로깅 (SLF4J를 사용한 예)
        Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
        logger.info("{} executed in {} ms", joinPoint.getSignature(), executionTime);
        
        return proceed;
    }
}
  • @Around 어드바이스를 사용하여 메소드 실행 전후로 로직을 감싸며, 실행 시간을 측정하고 로그를 출력합니다.
  • 포인트컷 표현식 "@annotation(com.example.LogExecution)"은 @LogExecution 어노테이션이 붙은 모든 메소드를 대상으로 합니다. 또한, 실제 패키지명은 프로젝트에 맞게 수정해야 합니다.

4. AOP 활성화

Spring Boot를 사용하는 경우 별도의 설정 없이도 AOP가 활성화됩니다.
일반 스프링 프로젝트라면 설정 클래스에 @EnableAspectJAutoProxy 어노테이션을 추가하여 AOP를 활성화해야 합니다

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
	/**
    *	기타 설정들
    */
}

5. 어노테이션 적용 예시

로깅을 적용하고자 하는 메소드에 커스텀 어노테이션을 붙입니다. 예를 들어, 서비스 클래스의 메소드에 적용할 수 있습니다.

@Service
public class SomeService {

    @LogExecution
    public void performTask() {
        // 비즈니스 로직 실행
    }
}

이제 performTask() 메소드가 호출될 때마다, LoggingAspect에서 정의한 로직에 따라 메소드의 실행 시간 등 로그가 자동으로 기록됩니다.

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

0개의 댓글