AOP (Aspect Oriented Programming)

eugene·2024년 1월 25일
0

멘토님의 추천으로 공부하게 된 주제인데, 2차 프로젝트 마지막 부분에 고민했던 스웨거 적용, 커스텀 예외 적용, 로깅 등에 너무 필요한 주제를 시기 적절하게 RBF로 공부하게 되어서 좋았다!


1️⃣ AOP란?

  • 흩어진 관심사 : 코드에서 여기저기에 흩어져서 반복되는 코드 (로깅, 인코딩, 보안, 에러체크 등)
  • 흩어진 관심사를 모아 모듈화 시키고, 핵심적인 비즈니스 로직에서 분리해 재사용 하도록 함
  • OOP(객체 지향 프로그래밍)을 돕기 위한 보조적인 기술로, 핵심적인 관심 사항과 공통 관심 사항으로 분리시키고 각각을 모듈화 시키는 것을 의미

2️⃣ 주요 용어

  • Aspect : 하나의 모듈. Advice + PointCut → AOP의 기본 모듈이며, 싱글톤 형태의 객체로 존재
  • Advice : 해야할 일들에 대한 정보
  • Joint Point : Advice가 적용될 위치, 끼어들 수 있는 지점, 메서드 진입 지점 등 다양한 시점 중 어디에 적용해야하는지에 대한 정보
  • Point Cut : JointPoint의 상세 스펙을 정의한 것. 구체적으로 Advice가 실행될 시점
  • Target : Advice가 적용되는 대상 (클래스, 메서드 등)

3️⃣ 스프링 AOP의 특징

  • 프록시 패턴을 이용해 AOP 효과를 냄
  • 스프링 빈에만 AOP를 적용할 수 있음

관련 어노테이션

  • @Aspect : Spring Container에게 AOP 담당 객체임을 알리는 역할 / 내부에 반드시 PointCut 설정과 Advice 구현이 필요
  • @PointCut : Spring Container에게 객체 생성하도록 지정
  • @Before(”${pattern}”) : 지정한 패턴에 해당되는 메서드가 실행되기 전에 동작 / 이 어노테이션이 붙은 메서드의 반환값은 void 이어야 함
  • @After(”${pattern}”) : 지정한 패턴에 해당되는 메서드가 실행된 후에 동작 / 이 어노테이션이 붙은 메서드의 반환값은 Object 이어야 함
  • @AfterReturning : AOP가 적용될 메서드가 에러 없이 성공적으로 실행된 이후의 시점
  • @AfterThrowing : AOP가 적용될 메서드에서 에러가 발생해 Exception을 던지는 시점
  • @Around(”${pattern}”) : 지정된 패턴에 해당되는 메서드가 실행 전, 실행 후 모든 부분에서 동작 / 이 어노테이션이 붙은 메서드의 반환 값은 Object이어야 함

(참고) AspectJ 프레임워크

The AspectJ Project | The Eclipse Foundation

  • 자바 프로그래밍 언어에 대한 완벽한 관점 지향 확장
  • 횡단 관심사의 깔끔한 모듈화
    - 오류 검사 및 처리
    - 동기화
    - 성능 최적화 (캐싱)
    - 모니터링 및 로깅

4️⃣ AOP 적용 방식

  • 컴파일 시점 : .class 를 만드는 순간 부가기능을 붙임
    - 특별한 컴파일러를 이용해야 하고 복작함
  • 클래스 로딩 시점 : JVM 내부 클래스 로더에 보관 / java Instrumentation 검색 / 수많은 모니터링 툴들이 이 방식을 사용 (=로드타임 위빙)
    - -javaagent 옵션을 통해서 클래스 로더 조작기를 지정해야 하는데, 이 부분이 번거롭고 운영하기 어려움
  • 런타임 시점 (프록시) : 이미 자바의 main 메서드가 실행된 다음

5️⃣ 간단한 코드적용 - 로깅

// AppConfig.java

@Configuration
@ComponentScan(basePackages = "com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}
// Anotation 정의

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
}
// 로깅을 수행하는 Aspect 정의

@Aspect
@Component
public class LoggingAspect {

    @Before("@annotation(LogExecutionTime)")
    public void logExecutionTime(JoinPoint joinPoint) {
        System.out.println("Before method execution: " + joinPoint.getSignature().getName());
    }

}
// MyService의 main 메서드 실행

@Component
public class MyService {

    @LogExecutionTime
    public void doSomething() {
        System.out.println("Inside doSomething method");
    }

    @LogExecutionTime
    public void doAnotherThing() {
        System.out.println("Inside doAnotherThing method");
    }

    public static void main(String[] args) {
        // Spring 컨텍스트 초기화
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 빈(MyService)을 가져와서 메소드 호출
        MyService myService = context.getBean(MyService.class);
        myService.doSomething();
        myService.doAnotherThing();

        // 컨텍스트 종료
        context.close();
    }

}


이번 프로젝트를 진행하면서 예외처리 시에 중복적인 코드들이 발생했고, 시간 관계상 더 찾아보지 않고 중복코드를 그냥 감수해서 코드를 작생했다. Aspect를 잘 활용한다면 이런 부분들을 간소화 해서 가독성이 뛰어난 코드를 작성할 수 있을 것 같다는 생각을 했다

이후에 @EnableTransactionManagement 어노테이션을 config 파일에 설정해서 트랜잭션 관리 또한 할 수 있다는 글을 보았는데, 직접 코드에 적용해 보고 싶다


이외에도 다양한 경우에 AOP를 적용하는데,

  • 보안 관련 작업: 인증, 권한 부여 등과 같은 보안 관련 작업을 여러 메소드에 적용해야 할 때, AOP를 사용하여 보안 관련 코드를 중앙화
  • 성능 모니터링: 메소드 호출 시간을 측정하거나 메소드 실행 횟수를 세는 등의 성능 관련 작업을 수행할 때, AOP를 활용하여 중복을 줄이고 코드의 가독성을 높임
  • 캐싱: 메소드의 결과를 캐싱해야 하는 경우, AOP를 사용하여 캐싱 로직을 분리할 수 있음
  • 예외 처리: 여러 메소드에서 발생하는 예외를 특정 방식으로 처리해야 하는 경우, AOP를 사용하여 예외 처리 로직을 모듈화할 수 있음

[스프링 핵심 원리 - 고급편] 강의에 꼼꼼하게 설명해 주셔서 이번에는 용어 정리까지만 보고 다른 부분들은 간단하게 공부했다.. 최종프로젝트 시작 전까지 틈틈히 강의 이어서 듣고 있는데 원리에 대한 부분을 더 상세하게 이해할 수 있어서 좋았다 (완강 화이팅)

profile
뽀글뽀글 개발공부

0개의 댓글