본문 바로가기

Spring

스프링 aop

스프링 AOP는 Aspect Oriented Programming의 약자이며, 관점 지향 프로그래밍입니다.

관점 지향 프로그래밍의 "관점 지향이란"   크게 핵심적인 관점과 부가적인 관점으로 나누어서 각각 모듈화를 하겠다는 것입니다.(관심사 분리)

 

예를 들어보자.

한 개발자가 개발 중에 있는데, 갑자기 모든 호출되는 메서드의 소요시간을 알고 싶다며, 모든 메서드에 소요시간을 구하는 로직을 구현을 해야 한다..

 

메서드가.... 1만 개라면..? 할 수야 있겠지만 엄청나게 오래 걸릴 것이다..

이런 식으로 개발을 하게 된다면..? 

  • 중복 코드 발생 -> 모든 코드에 똑같이 반복되는 코드가 생긴다. 흩어진 관심사(Crosscutting Concerns)
  • 핵심 로직과 부가적인 로직으로 인하여 service단에서 핵심 로직에 말고도 또 부가적인 로직에도 신경을 써야 함.

 

 

아까 위에서 말했다시피 핵심 관심사와 부가적인 관심사를 분리를 하여 모듈화를 하고 관리를 하면 

좀 더 객체지향스러워(?) 진다. 

 

 

AOP의 용어 정리

 

  • Target
    • 핵심기능을 가지고 있는 모듈로써 부가기능을 부여할 대상이다.(핵심 로직이라고 생각하면 된다.)
  • Advice 
    • 실질적으로 부가기능을 담은 구현체이다(실질적인 부가기능이다)
  • PointCut
    • Advice를 적용할 타깃의 메서드를 선정하는 방법(부가기능을 "어디에 적용할 것인지"->모든핵심 로직에 넣을 것인지 해당원하는 핵심로직에 넣을 것인지)
  • JoinPoint
    • Advice 적용될 수 있는 위치 (부가기능을 핵심 로직이 실행 전, 실행 후 등등 Adivce를 실행) 
  • Aspect 
    • Adivce+PointCut을 합친 개념이다.
    • 싱글톤으로 존재한다.
    • AOP 개념을 적용하면 핵심기능 코드 사이에 침투된 부가기능을 독립적인 애스펙트로 구분해 낼 수 있다.
    • 구분된 부가기능 애스펙트를 런타임 시에 필요한 위치에 동적으로 참여하게 할 수 있다.
  • Proxy
    • 프락시 기반이다.
    • 스프링에서는 Aop동작을 Proxy가 가로채어서 Advice의 부가기능을 실행 후 Target의 핵심기능을 실행한다.
  • Weaving
    • 포인트 컷에 의해서 결정된 타깃의 조인 포인트에 부가기능(advice)을 삽입하는 과정을 뜻한다.
    • AOP가 핵심기능(타깃)의 코드에 영향을 주지 않으면서 필요한 부가기능(advice)을 추가할 수 있도록 해주는 핵심적인 처리과정이다.

joinPoint

  • @Around (메서드 실행 전후)
    • 타깃 메소드 호출전과 후에 Advice기능을 수행한다.
  • @Before (이전)
    • Advice 타깃 메소드가 호출되기 전에 Advice 기능을 수행
  • @After (이후)
    • 타깃 메소드의 결과에 관계없이(즉 성공, 예외 관계없이) 타겟 메소드가 완료 되면 Advice기능을 수행
    • 무조건 실행된다고 보면된다.
  • @AfterReturning (정상적 반환 이후)
    • 타겟 메소드가 성공적으로 결과값을 반환 후에 Advice기능을 수행
  • @AfterThrowing (예외 발생 이후)
    • 타겟 메소드가 수행 중 예외를 던지게 되면 Advice기능을 수행

 

PointCut 종류

 

  • args()
    • 메소드의 인자가 타겟 명세에 포함된 타입일 경우
    • ex) args(java.lang.Long) 
  • @args()
    • 메소드의 인자가 타겟 명세에 포함된 어노테이션 타입을 갖는 경우
  • execution()
    • 접근 제한자, 리턴 타입, 인자 타입, 클래스/인터페이스, 메서드명, 파라미터 타입, 예외 타입 등을 전부 조합 가능한 가장 세심한 지정자
    • 대부분 이것을 사용하며, 세세하게 다 적용될 수 있음.
  • within()
    • execution 지정자에서 클래스/인터페이스까지만 적용된 경우
    • 즉, 클래스 혹은 인터페이스 단위까지만 범위 지정이 가능하다.
    • exectuion 지정자보다는 덜 세세함.
  • @within()
    • 주어진 어노테이션을 사용하는 타입으로 선언된 메서드
  • this()
    • 타깃 메소드가 지정된 빈 타입의 인스턴스인 경우
  • target()
    • this와 유사하지만 빈 타입이 아닌 타입의 인스턴스인 경우
  • @target()
    • 타깃 메소드를 실행하는 객체의 클래스가 타겟 명세에 지정된 타입의 어노테이션이 있는 경우
  • @annotation
    • 타겟 메서드에 특정 어노테이션이 지정된 경우
    • 내가 지정한 부분만 어노테이션을 사용하여서 Advice를 적용할 수 있음.

 

 

위에 예를 들었다시피 메서드 별로 시간 측정을 하기를 원한다.

 

모든 메서드는 아니고 Controller, Service Layer의 Method들의 시간 측정을 원한다.

하는 방법은 여러 가지이다 @annotation을 지정하여 할 수도 있지만, @annotation은 특정 어떠한 타깃에만 소수로 적용될 때 좋은 것 같다.

 

내가 적용한 방법은 타깃의 핵심 로직 메서드를 호출 전에 time을 찍고 핵심로직 수행 후에도 time을 찍어서 측정을 할 것이기 때문에 @Around advice를 적용을 하여서 구현한다.

@Aspect
@Component
@Slf4j
public class TimeTraceAop {

    //컨트롤러 포인트컷
    @Pointcut("within(com.example.yoonFood.controller..*)")
    private void getControllerTime(){

    }
    //서비스 포인트컷 
    @Pointcut("within(com.example.yoonFood.service..*)")
        private void getServiceTime(){

    }

    @Around("getControllerTime() || getServiceTime()")
    public Object methodControllerTime(ProceedingJoinPoint proceedingJoinPoint){
        Object result = null;
        long start = System.currentTimeMillis();
        String methodName = proceedingJoinPoint.getSignature().getName();
        log.info("Start:  실행 메서드 :{} ",methodName);


        try {
            result = proceedingJoinPoint.proceed();
            long end = System.currentTimeMillis();
            log.info("End :  실행 메서드 :{} ,수행시간 : {}",methodName ,end-start+"ms" );
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

        return result;
    }

}

측정을 하여서 log를 띄우는 건 개발자 스타일마다 다른 것이고.. 나는 메서드명을 띄었다 아니면 ToString을 이용하여서 해도 된다 (이건 개발자 맘!)

 

@Around의 포인트 컷은 @PointCut으로 위에화 같이 따로 분리하여서 설정하여도 되고

ex) @Around("execution(com.example.yoonFood..*)")등으로 바로 설정해도 된다.

 

포인트 컷 지정자는 여러 가지 조합이 많기 때문에 자기가 원하는 스타일대로 구글링을 해서 사용을 하면될 것 같다..

 

그리고 측정 중에 Controller와 Service Layer는 연관관계로 묶여있기 때문에(의존성이 주입되어 있기 때문에)

대부분의 Controller를 호출을 하면, Service의 method를 호출을 한다.

그래서 Controller 호출 -> Service호출 -> Service 끝-> Controller끝 이런 식으로 진행이 된다.

 

 

추가로 

구글링을 해서 인터넷에 자료를 검색을 하는 중에 대부분이 @Around,@Before,@After와 같이 joinPoint를

Advice라고 설명을 하는 것 같다.

Advice는 부가기능을 포함한 그 자체인데... JoinPoint 뜻도 Advice를 어디에 적용을 하는가에.. 뜻인데..

이것 때메 이해 하기가 쫌 어려웠다

아님 말고 이상 끝!

 

 

Reference

https://jojoldu.tistory.com/71?category=635883

'Spring' 카테고리의 다른 글

Spring 올바른(?)빈주입?  (0) 2023.02.06
스프링-시큐리티 UsernamePasswordAuthenticationFilter  (0) 2022.12.18
Interceptor 예외처리  (0) 2022.12.11
스프링 배치  (0) 2022.11.23
세션관리  (0) 2022.11.15