본문 바로가기
Java | Spring/Spring 입문

[스프링 입문] 7. AOP

by 동기 2022. 4. 9.
반응형

AOP

AOP란?

AOP Aspect(측면,양상) Oriented(지향) Programming의 약자로 관점 지향 프로그래밍이라고 불린다. 관점 지향은 쉽게 말해 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하겠다는 것이다. 여기서 모듈화란 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것을 말한다. 
출처: https://engkimbs.tistory.com/746 [새로비]

 

AOP가 필요한 상황

모든 메소드의 호출 시간을 측정하고 싶다면?

( 천개의 메소드에 시간을 측정하라는 지시가 있었고 , 지루한 시간을 버텨내며 작성하였으나, 전부 ms단위로 변경하라는 지시가 내려진다면? 또 반복적이고 지루한 작업을 하게 될 것이다.)

 

예제로 MemberService의 join메소드의 실행시간을 측정해 보자.

System.currentTimeMillis() 를 이용해서 확인할 수 있다.

    @Transactional
    public Long join(Member member){
        long start = System.currentTimeMillis();
        try {
            validateDuplicateMember(member);
            memberRepository.save(member);
            return member.getId();
        }finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish-start;
            System.out.println("join = "+timeMs+"ms");
        }
    }

테스트 결과

이렇게 측정은 가능하다.

 

다만 메소드가 많을경우가 문제인데, 메소드 전부 측정을 해야한다면, 메소드가 1000개 일 경우  start 시간, finish시간, 결과시간 을 1000번 반복해서 작성해줘야한다. ( 개발 생산성 바닥..)

 

공통 관심사항(cross-cutting concern) vs 핵심 관심 사항(core concern)

이것을 해결하고자 한다면, 어떠한 상황인지 살펴보아야 한다.

먼저, 회원가입, 회원 조회 등의 메소드에 시간을 측정하는 기능은 메소드의 핵심 관심 사항이 아닌, 공통 관심 사항이다.

메소드의 핵심 비즈니스 로직과 시간을측정하는 공통 관심 사항이 섞여서 유지보수가 어려우며, 시간을 측정하는 부분을 수정해야 하면 시간을 측정하는 기능을 쓰는 모든 메소드를 찾아서 고쳐줘야 한다.

하지만 시간을 측정하는 로직을 별도의 공통 로직으로 만들기가 매우 어렵다.

공통 관심사항과 핵심 관심사항을 분리하고 싶다.

이 때 쓰는것이 AOP 이다!

 

시간 측정 AOP 등록

aop 패키지 및 TimeTraceAop 클래스 작성

@Aspect
@Component
public class TimeTraceAop {

    public Object excute(ProceedingJoinPoint joinPoint) throws Throwable{
        long start = System.currentTimeMillis();
        System.out.println("START :"+joinPoint.toString());
        try {
            return joinPoint.proceed();

        }finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("END :"+joinPoint.toString()+" "+timeMs+"ms");
        }
    }
}

@Aspect 추가 후, ProceedingJoinPoint 를 인자로 받는 excute() 메소드를 작성한다.

또한 클래스에 @Component를 추가해주거나, SpringConfig에 @Bean으로 등록하여 컨테이너에 올려주고 쓰도록 한다.

(Component로 써도 되지만, 잘 알려지고 정형화된것으로 쓰이는 것이 아닌 조금 유니크한 기능이기때문에 Config에서 Bean등록을 해주는것이 좀 더 개발자가 직관적으로 알기 좋음. 해당 예제에서는 @Component로 등록해서 진행하였다.)

 

원하는 곳에 공통 관심사항 적용(타게팅)하기

@Aspect
@Component
public class TimeTraceAop {

     @Around("execution(* DevDglee.hellospring..*(..))")
    public Object excute(ProceedingJoinPoint joinPoint) throws Throwable{
			.
			.
			.
    }
}

@Around() 어노테이션을 추가하고, excution() 메소드에 내에 패키지 설정 및 클래스 설정이 가능하다.

현재 작성한 것은 hellospring의 모든 하위 패키지의 모든 클래스에 설정이 된다.

 

📌사용 방법에 대해 좀 더 자세히 알고싶다면 매뉴얼을 참조하자.( 실무에서는 전체 기능의 5% 도 안쓴다고 하니, 필요할때 검색해서 쓰면 될것같다)

 

홈화면 및 회원목록을 조회했을때에 END 에 시간이 찍히는 것을 볼 수 있다.

이렇게 원하는곳을 지정해서 편하게 볼 수 있어서, 어느 지점에서 병목현상이 일어나는지도 알 수 있다.

 

앞으로 변경사항이 필요하면 AOP 부분만 바꾸면 된다.

 

반응형

댓글