AOP?

Dobi·2024년 3월 20일

Spring

목록 보기
1/6
post-thumbnail

AOP (Aspect Oriented Programming)

AOP는 관점 지향 프로그래밍이라고 불린다.
관점(Aspect) 지향은 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 부가적인 관점(기능)을 각각 Aspect라는 형태로 모듈화하겠다는 것이다.
모듈화란 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것을 말한다.

AOP에서 각 관점을 기준으로 로직을 모듈화한다는 것은 코드들을 부분적으로 나누어서 모듈화하겠다는 의미다. 이때, 소스 코드상에서 다른 부분에 계속 반복해서 쓰는 코드들을 발견할 수 있는 데 이것을 흩어진 관심사 (Crosscutting Concerns)라 부른다. 

AOP 그림

Aspect

Aspect는 AOP의 기본 모듈로 부가기능의 코드를 정의한(구현체) Advice와 어디에 적용할지를 결정하는 PointCut을 합친 개념이다.


AOP 주요개념

  • Aspect : 묶은 것. 흩어진 관심사를 하나의 모듈화한 것.
  • Target : 핵심기능을 담고있는 모듈로 부가기능인 Aspect가 적용이 되는 대상.
  • Advice : 해야할 일들에 대한 정보(구현체).
  • Join point : 지점. Advice를 끼워넣을 수 있는 지점(위치, 합류점).
    - 메서드 진입 지점, 생성자 호출 시점 등 다양한 시점에 적용가능
    - 예) 이 메소드를 실행할 때 이 Advice를 끼워 넣어라.
  • Pointcut : 어디에 적용해야 하는지에 대한 정보
  • Weaving :
    - PointCut에 의해서 결정된 Target의 Join point에 부가기능(Advice)를 삽입하는 과정
    - AOP가 핵심기능(Target)의 코드에 영향을 주지 않으면서 필요한 부가기능(Advice)를 추가하거나 변경할 수 있도록 해주는 처리과정이다.

AOP 적용방법

  • 컴파일 : 컴파일 후 별도의 추가 컴파일로 클래스 파일의 바이트 코드를 수정 적용하는것
  • 로드 타임 (= 로드 타임 위빙) :
    - 컴파일 자체는 순수하게 완료.
    - 해당 클래스 파일을 로딩하는 시점에 바이트 코드를 로딩하는 클래스 정보를 변경 적용
    - 로딩한 클래스 파일 자체는 그대로지만, 로딩한 JVM 메모리 상에는 적용된 상태로 로딩
    - 로드 타임에 java agent 설정을 해줘야한다. (약간의 성능 부하)
    - 다양한 문법 사용 가능.
  • 런타임 :
    - 해당 클래스의 빈을 만들 때, 프록시 빈을 만듬
    - 해당 클래스 빈 호출 직전에 필요한 일을 실행 후 호출.
    - 문법이 쉽고, 별도의 설정 등이 필요없다.

Spring AOP 특징

  • 프록시 기반의 AOP 구현체
  • 스프링 Bean에만 AOP를 적용할 수 있다.
  • 모든 AOP 기능을 제공하는 것이 목적이 아니라, 스프링 IoC와 연동하여 엔터프라이즈 애플리케이션에서 가장 흔한 문제(중복코드, 객체간 관계 복잡도 증가 등)에 대한 해결책을 제공하는 것이 목적.

Spring AOP : @AOP

  • @Aspect 어노테이션을 이용한 AOP 구현

gradle의 build.gradle에서 의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-aop'

@Aspect라는 어노테이션을 붙여서 이 클래스가 Aspect라는 것을 명시하고
@Component를 붙여 컴포넌트 스캔에 의해 빈으로 등록되도록 한다.

1 - 경로지정 방식

@Around 어노테이션은 타겟 메서드를 감싸서 Advice를 실행한다는 의미이다.

@Component
@Aspectpublic 
class PerfAspect {

	@Around("execution(* com.example..*.EventService.*(..))")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable{
      long begin = System.currentTimeMillis(); 
      Object retVal = pjp.proceed(); // 메서드 호출 자체를 감쌈
      System.out.println(System.currentTimeMillis() - begin); 
      return retVal; 
    }
}

2 - 어노테이션이 붙은 포인트에 실행하도록 하는 방식

@Component
@Aspectpublic 
class PerfAspect {
	@Around("@annotation(PerLogging)")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable{
      long begin = System.currentTimeMillis(); 
      Object retVal = pjp.proceed();
      System.out.println(System.currentTimeMillis() - begin); 
      return retVal; 
    }
}
// 어노테이션 등록
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface PerLogging {
}
// 어노테이션 적용
@Component
public class SimpleEventService implements EventService {
	@PerLogging
	@Override
    public void publishEvent() {
        System.out.println("Published an event");
    }
}

3 - 빈의 모든 메서드에 적용하는 방식

@Component
@Aspectpublic 
class PerfAspect {
  @Around("bean(simpleEventService)")
  public Object logPerf(ProceedingJoinPoint pjp) throws Throwable{
    long begin = System.currentTimeMillis(); Object retVal = pjp.proceed(); 
    System.out.println(System.currentTimeMillis() - begin); 
    return retVal; 
  }
}

Advice 어노테이션 종류

  • @Before :
    - 타겟 메소드가 호출되기 전에 어드바이스 기능을 수행
    - JoinPoint 앞에서 실행되는 Advice
  • @After :
    - 타겟 메소드가 완료 되면(성공 또는 예외 결과 상관없이) 어드바이스 기능을 수행
    - JoinPoint 뒤에 실행되는 Advice
  • @AfterReturning :
    - 타겟 메소드가 정상적으로 결과값을 반환 후에 어드바이스 기능을 수행
    - JoinPoint 메서드 호출이 정상적으로 종료된 후에 실행되는 Advice
  • @AfterThrowing : 타겟 메소드가 수행 중 예외를 던지게 되면 어드바이스 기능을 수행
  • @Around :
    - 어드바이스가 타겟 메소드를 감싸서 타겟 메소드 호출전과 후에 어드바이스 기능을 수행
    - Joinpoint 앞과 뒤에서 실행되는 Advice

참조

백기선 - 스프링 프레임워크 핵심 기술

profile
양말 받을 때까지 공부하는 개발자 도비

0개의 댓글