Spring 기능 - AOP ( Aspect Oriented Programming )

이정수·2025년 3월 23일

Spring

목록 보기
5/18

관점지향프로그래밍 (AOP : Aspect Oriented Programming) :

Business LogicCross Cutting Concern을 분리하여 모듈화하는 프로그래밍 기법.
▶ 어떤 logic을 기준으로 핵심적인 관점 , 부가적인 관점으로 나눠서 보고 해당 관점을 기준으로 각각 모듈화를 수행

Cross Cutting ConcernAspect 단위로 분리 후 Joint PointPointcut으로 지정하여 Joint Point메소드 호출인터셉트AdviceWeaving하여 핵심 Business Logic과 독립적으로 적용
AspectAdvice로서 작성한 코드를 Pointcut으로 지정한 특정 패키지 내부의 Spring Bean의 Method를 호출 시 인터셉트하여 적용

JavaAOP 종류 : Spring AOP , AspectJ

AOP 용도의 클래스 생성 시 뒤에 이름에 Aspect 키워드를 기입하는게 관례

LayerBusiness Logic에서 Logging, Security, Transaction등의 Cross Cutting Concern을 별도의 Aspect 로 분리하여 Boiler Plate Code를 줄이고 집중적으로 관리하여 유지보수를 쉽게 수행

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

공통관심사 ( Cross Cutting Concern )
어플리케이션의 여러 모듈에서 공통적으로 필요하지만 , 각 모듈Business Logic과는 별개인 기능
▶ 전반에서 코드중복( WET )을 유발하는 boiler plate code

。같은 기능의 코드가 여러곳에서 중복으로 사용하여 유지보수성코드가독성을 떨어뜨리는 원인
Spring AOP을 통해 Cross Cutting ConcernAspect로 분리하여 해결.

。주로 레이어드 아키텍처에서 분리된 각 계층의 공통으로 사용하는 Security (보안) , Performance(성능측정) , Logging(문제식별) 부분을 AOP로 구현

Compile 시점에서 실행되는 AOP 기능
。개발자에 의해 작성된 Java Source Code에서 기계어로 변환
Aspect , Advice , Weaver

Runtime 시점에서 실행되는 AOP 기능
빌드어플리케이션이 사용자에 의해 실행이 되는 시점
JoinPoint , Pointcut

Aspect
AOP에서 Cross Cutting Section을 정의한 Advice적용대상 (Pointcut)을 정의한 모듈
Aspect = Advice + Pointcut + JoinPoint

  • @Aspect : org.aspectj.lang.annotation.Aspect
    Spring AOP에서 Aspect 목적으로 Cross Cutting Concern을 구현하는 클래스에 선언하는 어노테이션
    ▶ 여러 모듈에서 동일하게 사용하는 Logging , Transaction , Security 등을 구현

    。해당 Annotation을 선언 시 해당 Class가 AOP 기능을 수행하는 Aspect임을 선언

    @Component처럼 Spring Bean으로 등록하는 Logic이 없으므로 @Configuration 또는 @Component를 추가로 선언하여 Spring Bean으로서 등록해 활용

Advice
。각 모듈Cross Cutting Concern에 해당하는 Code SectionAspect 클래스 내에 메서드로 지정 및 Advice 어노테이션을 선언
Join Point인터셉트하여 Advice 어노테이션이 적용된 메서드를 호출

인터셉트하여 실행할 메서드의 실행 시점에 따라서 @Before , @After , @Around등의 Advice 어노테이션이 존재.

// Aspect 부분
@Before(Pointcut 부분 : "execution(* com.wjdtn747.rest.webservices.aop_practice.AOPPractice1.*.*(..))")
    public void logMethodCall(JoinPoint joinPoint){
        // Advice 부분
        logger.info("logMethodCalled - {}",joinPoint);
    }

com.wjdtn747.rest.webservices.aop_practice.AOPPractice1.*.*(..))"의 하위 패키지 경로에 존재하는 모든 Spring Bean에서 실행되는 메서드들이 실행되기전 인터셉트하여 logMethoCall()을 실행

  • ProceedingJoinPoint : org.aspectj.lang.ProceedingJoinPoint
    Spring AOP에서 @Around Method의 매개변수로 전달되어 Advice로서 활용하여 AOP 적용 Method의 실행을 제어하는 역할의 Interface


    ProceedingJoinPoint객체.proceed()
    AOP 적용 Method를 실행.
    ▶ 실행을 지연하거나, 조건에 따라 실행을 취소가능.

    ProceedingJoinPoint객체.getArgs() :
    AOP 적용 Method매개변수배열로 가져오는 역할을 수행
    • @Before("AspectJ Pointcut") : org.aspectj.lang.annotation.Before
      JUnit@Before와 다르다.

      Spring AOP가 적용될 메서드가 실행되기전에 해당 어노테이션이 선언된 Method를 실행하도록 하는 Advice Annotation
      Business Logic이 수행되기 전에 실행될 부가기능( Logging , Authentication 검사 )을 정의 시 사용.

    • @After("AspectJ Pointcut")
      AOP 대상 Method가 실행된 후 예외발생에 상관없이 해당 Annotation이 선언된 Method가 항상 실행.
      AOP 대상 Method의 성공 / 예외여부와 관계없이 실행.

      。주로 Resource 정리, log 기록, Transaction 종료 등의 후처리 Method로서의 작업 수행 시 선언.

    • @AfterReturing(pointcut="AspectJ Pointcut",returning="반환될변수명")
      AOP 대상 Method가 실행 시 정상적으로 실행된 경우 해당 Annotation이 선언된 Method가 실행.
      AOP 대상 Method가 정상 실행 시 실행하므로 반환값을 사용가능

      Annotationreturning="예외변수명" 속성을 추가하여 AOP 적용 Method의 반환값을 활용가능.
    @AfterReturning(pointcut = "execution(* com.example.service.MyService.getData(..))", returning = "result")
        public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
            System.out.println("메서드 실행 성공 후: " + joinPoint.getSignature());
            System.out.println("반환된 값: " + result);
        }

    @AfterReturing(pointcut="AspectJ Pointcut",returning="반환값변수명") 정의 후 매개변수에 Object 반환될변수명 정의 시 AOP 적용 Method의 반환값을 활용 가능.
    AOP 적용 Method가 예외 발생 시 실행되지 않는다.

    • @AfterThrowing(pointcut="AspectJ Pointcut",throwing="예외변수명")
      AOP 대상 Method가 실행 중 예외가 발생된 경우 해당 Annotation이 선언된 Method가 실행.
      AOP 대상 Method가 예외 발생 시 실행하므로 Exception에 대한 정보를 사용가능

      Annotationthrowing="예외변수명" 속성을 추가하여 AOP 적용 Method에서 발생한 Exception instance를 활용가능.
     @AfterThrowing(pointcut = "execution(* com.example.service.MyService.process(..))", throwing = "ex")
        public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
            System.out.println("메서드 실행 중 예외 발생: " + joinPoint.getSignature());
            System.out.println("발생한 예외: " + ex.getMessage());
        }

    @AfterThrowing(pointcut="AspectJ Pointcut",throwing="예외변수명") 정의 후 매개변수에 Exception 예외변수명 정의 시 AOP 적용 Method에서 발생한 Exception instance를 활용 가능.
    AOP 적용 Method가 정상 실행 시 실행되지않는다.

    • @Around("AspectJ Pointcut") :
      AOP 적용 Method의 실행 전후를 모두 제어하는 기능을 제공하는 Annotation
      @Before + @After를 모두 합친 기능으로서 실행여부까지 제어가능.

      AOP 적용 Method 정상 실행 후 반환값을 임의로 변경가능.
      。Method 실행시간의 측정을 통한 성능측정이 가능.
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.Configuration;
    @Aspect
    @Configuration
    public class PerformanceTrackingAspect {
        public Logger logger = LoggerFactory.getLogger(getClass());
        // Pointcut으로 정의된 Package의 하위경로의 Class에서 호출되는 AOP 적용 Method를
        // Intercept하여 실행 전후의 시간을 측정.
        @Around("execution(* com.wjdtn747.rest.webservices.aop_practice.AOPPractice1.*.*(..))")
        public Object findExecutionTime(ProceedingJoinPoint proccedingjoinPoint) throws Throwable {
            // Timer 시작 시점
            long startTimeMilis = System.currentTimeMillis();
            // AOP 적용 Method를 실행 후 반환값을 변수로 assign.
            Object returnValue = proccedingjoinPoint.proceed();
            // Timer 종료 시점
            long endTimeMilis = System.currentTimeMillis();
            long durationTimeMilis = endTimeMilis - startTimeMilis;
            logger.info("@Around 적용 Aspect - {} Method 실행시간 {} ms", proccedingjoinPoint , durationTimeMilis);
            return returnValue;
        }
    }


    ▶ Pointcut으로 정의된 Package의 하위경로의 Class에서 호출되는 AOP 적용 Method를 Intercept하여 실행 전후의 시간을 측정.

    @Around Method의 매개변수에 ProceedingJoinPoint instance를 선언하여 ProceedingJoinPoint객체.proceed()@Around Method의 원하는 시점의 Advice에 기입하여 AOP 적용 Method이 실행되도록 설정.

    AOP를 통해 AspectAdvice로서 작성한 코드를 특정 Package 내부의 여러 Class의 Spring Bean의 Method 호출 시 Intercept하여 모두 적용 가능.
    ▶ 따로 해당 Class에 Advice 기능을 각각 구현할 필요가 없이 공통적으로 적용.

Weaver
AspectAdvice어플리케이션 모듈Business Logic을 결합하는 역할을 수행.
Application의 기존 코드에 Aspect를 적절한 지점과 Runtime 또는 Compile 시점을 선택하여 결합을 수행.

AOP FrameworkSpring AOP , AspectJWeaver의 역할로서 Weaving 작업을 수행.
Weaving : Pointcut으로 지정된 Join pointAdvice를 실제로 결합하는 행위

JoinPoint : org.aspectj.lang.JoinPoint
Pointcut으로 지정되어 호출AOP에 의해 인터셉트하는 메서드 부분
Advice가 적용될 수 있는 모든 위치를 의미.
Spring AOPJoinPoint인터셉트되는 Method 실행지점을 의미.

Join Point로서 Pointcut에 정의되어 인터셉트Spring BeanMethod의 이름, 매개변수, 반환값등의 정보를 JoinPoint instance에 포함하여 Aspect에서 Advice 어노테이션이 선언된 매개변수로 전달

// com.ktcloud.excercise.AOP 패키지의 하위 Spring Bean의
	// 모든 Method가 호출되기 전에 intercept하여 선언된 Method가 실행.
	@Before("execution(* com.ktcloud.excercise.AOP.*.*(..))")
	// JoinPoint를 통해 인터셉트한 Method의 이름, 매개변수, 반환값등의 정보를 매개변수로 제공.
	public void beforeLogMethodCall(JoinPoint joinPoint) {
		// Logger Logic 구현
		logger.info("beforelogMethodCalled - {}",joinPoint);
      // beforelogMethodCalled - execution(void com.ktcloud.excercise.AOP.AOPPractice.run(String[]))
	}

JoinPoint객체.getSignature() , JoinPoint객체.getArgs()
인터셉트Method명 , Class 정보, 매개변수 등을 가져올 수 있음.

Pointcut
AOP에서 Advice를 적용하도록 인터셉트할 특정 JoinPoint를 정의 하는 표현식
Join Point로서 Pointcut을 설정하여 범위 지정 시 해당 범위의 Spring Bean에서 발생하는 Method 호출인터셉트

Pointcut의 조건이 참일 경우, Advice가 실행됨.

Spirng AOP에서는 "execution" , "within" , "args" 등의 AspectJ Pointcut 표현식을 사용하여 PointcutAdvice 어노테이션@Before(AspectJ Pointcut)에 정의.
ex) @Before("execution(* 패키지명.*.*(..))")
▶ 해당 패키지Spring Bean메서드가 실행되기 전 @Before가 선언된 Advice 메서드를 실행

ex ) execution(* 패키지명.*.*(..))" : 특정 Package의 1단계 하위 모든 Class에서 호출되는 모든 MethodIntercept하여 선언된 Method가 실행됨.

  • @Pointcut("AspectJ Pointcut") : org.aspectj.lang.annotation.Pointcut;
    pointcut 표현식을 통해 특정 JoinPoint 범위를 지정하여 다른 AOP 어노테이션들에게 참조용도로 활용되는 Annotation.

    。기존의 모든 AOP 어노테이션에 정의한 Pointcut특정Package경로를 정의하는 AspectJ Pointcut 표현식을 포함하는 @Pointcut Method의 경로로 통일
    Package경로가 변경되더라도 모든 AOP 어노테이션을 수정하는게 아닌, @Pointcut에 정의된 AspectJ Pointcut 표현식을 수정

    AspectJ Pointcut 표현식 종류

    • @Pointcut("execution(Package경로)") :
      。지정된 범위의 Package 경로의 하위 ClassSpring BeanMethod 또는 Class를 호출할 경우 Intercept하는 Pointcut.
    @Pointcut("execution(* com.wjdtn747.rest.webservices.aop_practice.AOPPractice1.*.*(..))")
        public void DataPackageConfig(){}
    • @Pointcut("bean(*Service*)") :
      ▶ 이름에 "Service"가 들어간 Spring Bean를 포함하는 Method 호출Intercept.

    • @Pointcut("@annotation(Annotation경로)") :
      AnnotationPointcut으로 활용 시 선언
    @Pointcut("@annotation(com.wjdtn747.rest.webservices.aop_practice.aspects.Tracktime)")
    public void TracktimePointcut(){}
    
profile
공부기록 블로그

0개의 댓글