Spring

Spring AOP

나도관 2023. 7. 14. 13:02

회사에서 '스프링 프레임워크 첫걸음' 이라는 책을 소개 받아서 제대로 모르는 것들에 대해서 복습을 진행하고 있다. AOP의 개념에 대해서 혼동하고 있던 부분이 있어 다시금 학습 기록을 남겨두려고 한다.

 

AOP란?

AOP(Aspect Oriented Programming)은 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어 보고 그 관점을 기준으로 모듈화하는 것을 말하며, 어떤 로직에 공통된 관심사로 작성된 로직이 있다면 Aspect로 모듈화하여 재사용하는 것이다.

 

 

@Aspect 어노테이션으로 해당 클래스가 Aspect임을 표시하고, @Component를 통해 빈에 등록한다.

 

@Aspect
@Component
public class UseTimeAop {

}

 

각 클래스 마다 중심적 관심사 (처리 목표), 횡단적 관심사 (공통으로 사용하는 로직)을 분류하여 공유하는 횡단적 관심사를 Aspect로 지정한다. Aspect에서 대상 클래스와 메서드를 실행 시점을 조정하여 사용할 수 있다.

 

간단한 예제를 통해 설명해보도록 하겠다.

Spring Boot 애플리케이션 실행 시에, 간단한 문장을 출력하는 예제이다.

 

Application (Main 클래스)

@SpringBootApplication
public class Application {
    public static void main(String[] args){
        SpringApplication.run(Application.class, args).getBean(Application.class).execute();
    }
    @Autowired
    Greet greet;

    private void execute(){
        greet.greeting();
    }
}

Main 클래스에서 Greet 클래스를 빈으로 등록해주었다.

 

Greet  구현체

public interface Greet {
    void greeting();
}


@RequiredArgsConstructor
@Component
public class GreetImpl implements Greet{

    @Override
    public void greeting() {
        System.out.println("---------------");
        System.out.println("좋은 아침입니다.");
        System.out.println("---------------");
    }

 

Aspect 클래스 (횡단적 관심사)

@Aspect
@Component
public class SampleAspect {
    @Before("execution(* com.twin.jvoice.contest.common.aop.greet.*Greet.*(..)))")
    // com.twin.jvoice.contest.common.aop.greet 에서 Greet로 끝나는 모든 메서드에 대해
    public void beforeAdvice(JoinPoint joinPoint){
        //시작 부분
        System.out.println("======== Before Advice ========");
        //날짜 출력
        System.out.println(new SimpleDateFormat("yyyy/MM/dd").format(new java.util.Date()));
        //메서드 이름 출력
        System.out.println(String.format("메서드:%s", joinPoint.getSignature().getName()));
    }

Aspect 클래스에서는 Advice 의 실행시점에 해당하는 어노테이션을 설정해주고, 어떤 클래스의 메서드를 실행할 것인지 excution() 내에 경로를 지정해준다.

 

예제 같은 경우에는 애플리케이션 시작 시에, Greet 클래스의 greeting() 이라는 메서드를 실행시킬 것이다. (Main 클래스)

 

만약 Greet 클래스 내부의 모든 메서드가 실행될 경우에(execution() 내부 경로), beforeAdvice 함수가 실행될 텐데 그 시점이 메서드 실행 전(@Before) 이다.

 

 

실행 결과

 

Aspect 내 Advice의 실행 시점을 조정하는 어노테이션은 여러가지가 있으므로, 구글링해보길 바란다.

 

@Around

    @Around("execution(* com.twin.jvoice.contest.common.aop.greet.*Greet.*(..)))")
    public void aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //시작 부분
        System.out.println("이 함수는 메서드 마다 실행된다.");
        //메서드 이름 출력
        System.out.println(String.format("메서드:%s", joinPoint.getSignature().getName()));
        joinPoint.proceed();
        System.out.println("==============실행 완료==============");
    }

Around는 Advice 내부에서 실행 시점을 설정할 수 있다. JoinPoint.proceed() 는 대상 메서드의 실행을 의미한다.

 

@Around 실행 결과

 

 

이처럼 AOP를 통해 중복되는 코드를 피하고, 클래스를 모듈화하여 필요한 곳에서 가져다 재사용할 수 있다.