본문 바로가기
Study

[스터디] AOP의 정의와 활용

by DuncanKim 2022. 9. 1.
728x90

[스터디] AOP의 정의와 활용

스프링의 기본 원리를 이제까지 알아보았는데, 마무리 과정에 이르렀다. AOP(Aspect-Oriented Programming)이 남았다. AOP는 스프링의 프로그래밍 모델 중 하나이다. 번역을 하면 관점 지향 프로그래밍이라고 할 수 있다.

 

관점이라는 말 보다는 실제 AOP가 왜 사용되는지, 어떻게 활용되는지를 알아가다 보면 이것이 어떤 모델인지를 충분히 이해할 수 있다.

 

 

1. AOP를 사용하는 이유(WHY)

 

 스프링 프로젝트에 관심이 있다면, 누구든 이 에피소드는 한 번은 들어봤을 것이다.

A 팀장 : B님 프로젝트 관련해서 해줘야 할 일이 있을 것 같은데... 간단한 거거든요?
B 신입 : 네! 뭐든 말만해주세요(의욕 과다)!
A 팀장 : 그래요. 우리 프로그램 성능 측정하는 코드를 조금 추가해야 되는데, 시작시간하고 종료시간만 딱 체크해서 구동 시간을 체크해주면 되는데, 전체 프로그램 클래스 안에 코드를 넣어서 시간 측정을 해야 해요. 근데 그렇게 어렵지는 않으니까 구글링 조금만 해서 코드를 넣어놔 주세요.
B 신입 : 네! 알겠습니다!

...... (새벽 3시)

B 신입 : 아니 코드 복붙만 몇 시간째여... 이것 밖에 방법이 없나? 에휴 새끼손가락이 남아나질 않는다....

(톡.. 토독... 토도도독. 토토토토독....)

..... (그 다음날 9시)

A 팀장 : B님! 코드 다 추가했죠?
B 신입 : 네.... 기능도 다 잘됩니다.... 한 번 돌려보시죠...
A 팀장 : 잘했네! 근데 여기에 부가기능이 들어가야하는데, 조회하는 메서드만 시간이 어느정도 걸리는 지 알아야겠어요. 다른 것들은 이제 빼고 그것만 남겨둡시다.
B 신입 : 네? 저는 이만 집에 가보겠습니다.... (사표 제출)

 

B 신입은 스프링을 공부하고 들어오지 않았고, 전형적인 9 to 6 개발자라고 추정된다. 일단 이렇게 귀찮은 일을 부여받았을 때는 더 효율적으로 할 수 있는 방법이 없나,,, 하는 생산적 귀찮음을 발생시켜야 하나 그렇지 못하였고, AOP의 개념을 알지 못하고 있다.

 

우리는 여기에서 B 신입이 그 일을 해내는 데 까지 생각해야 할 포인트 들을 집어낼 수 있다.

1) 똑같은 코드를 반복해서 붙여넣는 것이다.

2) 쓸 지도 안 쓸지도 모르고, 언제 없어질지도 모른다(그 클래스에 꼭 필요한 기능이 아니다).

 

그렇다. 이렇게 클래스들에 똑같은 것이 반복적으로 들어가 있으면서, 추후에 쓸 것인지 안쓸 것인지 모르는 기능을 횡단 관심사라 하고, 이 기능들을 따로 모아 모듈화하여 재사용하는 기법을 AOP 라고 한다. 이와 같은 맥락에서 AOP는 핵심 기능만 존재해야 한다는 SRP(단일 책임 원칙)에 따른 프로그래밍 모델이라고 할 수 있다.

 

또다른 비유로는, 양념 치킨이든, 후라이드 치킨이든, 숯불치킨이든 앞 과정에 닭을 잡는 것과 포장하는 것은 똑같은 과정을 거친다고 볼 수 있다. 이것만 따로 하는 직원을 두고, 조리장은 그 치킨을 어떻게 더 맛있게 만들 것인가를 분리하는 '분업화 과정' 이라고 보면 좋겠다.

 

(깔끔한 요약 : 중복, 재사용을 위한 프로그래밍 모델이다.)

 

 

2. AOP 용어

 

아래 용어들은 Spring에서만 사용되는 용어들이 아닌 AOP 프레임워크 전체에서 사용되는 공용어다.


타겟 (Target)
부가기능을 부여할 대상. 핵심기능을 담당하는 메서드 또는 클래스를 지칭한다.

애스펙트 (Aspect)
객체지향 모듈을 오브젝트라 부르는것과 비슷하게 부가기능 모듈을 애스펙트라고 부르며, 핵심기능에 부가되어 의미를 갖는 특별한 모듈이다. 애스펙트는 부가될 기능을 정의한 어드바이스와 어드바이스를 어디에 적용할지를 결정하는 포인트컷을 함께 가지고 있다.

어드바이스 (Advice)
실질적으로 부가기능을 담은 구현체. 어드바이스의 경우 타겟 오브젝트에 종속되지 않기 때문에 순수하게 부가기능에만 집중할 수 있다. 어드바이스는 애스펙트가 '무엇'을 '언제' 할지를 정의하고 있다.

포인트컷 (PointCut)
부가기능이 적용될 대상(메소드)를 선정하는 방법. 어드바이스를 적용할 조인포인트를 선별하는 기능을 정의한 모듈을 애기한다.

조인포인트 (JoinPoint)
어드바이스가 적용될 수 있는 위치. 다른 AOP 프레임워크와 달리 Spring에서는 메서드 조인포인트만 제공한다.

프록시 (Proxy)
타겟을 감싸서 타겟의 요청을 대신 받아주는 랩핑(Wrapping) 오브젝트. 클라이언트에서 타겟을 호출하게 되면 타겟이 아닌 타겟을 감싸고 있는 프록시가 호출되어, 타겟 메소드 실행전에 선처리, 타겟 메소드 실행 후, 후처리를 실행시키도록 구성되어 있다.

 

위빙 (Weaving)
지정된 객체에 애스팩트를 적용해서 새로운 프록시 객체를 생성하는 과정.
예를 들어 A라는 객체에 트랜잭션 애스팩트가 지정되어 있다면, A라는 객체가 실행되기전 커넥션을 오픈하고 실행이 끝나면 커넥션을 종료하는 기능이 추가된 프록시 객체가 생성되고, 이 프록시 객체가 앞으로 A 객체가 호출되는 시점에서 사용된다.

 

 

3. AOP를 활용하는 방법(HOW)

Performance.java

@Aspect
public class Performance {

    @Around("execution(* com.blogcode.board.BoardService.getBoards(..))")
    public Object calculatePerformanceTime(ProceedingJoinPoint proceedingJoinPoint) {
        Object result = null;
        try {
            long start = System.currentTimeMillis();
            result = proceedingJoinPoint.proceed();
            long end = System.currentTimeMillis();

            System.out.println("수행 시간 : "+ (end - start));
        } catch (Throwable throwable) {
            System.out.println("exception! ");
        }
        return result;
    }
}

스프링 프로젝트에서 service를 담당하는 BoardService의 getBoards()의 수행시간을 알아보는 것이다.

 

@Around의 경우, 위에서 이야기하는 advise 인데, 애스펙트가 무엇을, 언제 할 지를 의미한다. 이 코드에서 무엇은 calculatePerformanceTime() 메서드를 지칭한다. 그리고 언제는 @Around인데, 시점은 담당하는 것은 around 이외에도 많다.

 

@Before (이전)
: 어드바이스 타겟 메소드가 호출되기 전에 어드바이스 기능을 수행

@After (이후)
: 타겟 메소드의 결과에 관계없이(즉 성공, 예외 관계없이) 타겟 메소드가 완료 되면 어드바이스 기능을 수행

@AfterReturning (정상적 반환 이후)
: 타겟 메소드가 성공적으로 결과값을 반환 후에 어드바이스 기능을 수행

@AfterThrowing (예외 발생 이후)
: 타겟 메소드가 수행 중 예외를 던지게 되면 어드바이스 기능을 수행

@Around (메소드 실행 전후)
: 어드바이스가 타겟 메소드를 감싸서 타겟 메소드 호출전과 후에 어드바이스 기능을 수행

 

@Around 다음 괄호에 표시된 "execution(* com.blogcode.board.BoardService.getBoards(..))"의 경우, 포인트컷 표현식이라고 한다. 이중 'execution'은 지정자라고 하며, * com. .... .getBoards(..)는 타겟 명세라고 한다.

 

타겟 명세의 경우, BoardService.getBoards()를 메서드로 지정하였다라는 의미이다. 앞에 붙은 * 은 모든 타입이 리턴이 가능하다는 것이다. 리턴 타입을 임의로 다르게 정할 수도 있다.

 

지정자는 execution을 포함하여 아홉 가지가 있는데, 이는 나중에 살펴보기로 한다.

 

 

Application.java

@SpringBootApplication
@RestController
@EnableAspectJAutoProxy //오토 프록싱
public class Application implements CommandLineRunner{
	
    @Bean
    public Performance performance() {
        return new Performance();
    }
 
 	...
}

@Bean을 추가하고, 어노테이션을 해석할 수 있도록 설정을 추가한다.

 

이렇게 되면, getBoards()의 수행 시간을 BoardService에 특정 코드를 추가하지 않고도 구할 수 있다.

 

 

이런 방식으로 하는 AOP는 성능 검사, 트랜잭션 처리, 로깅 등에 활용된다.

 

 

4. 스프링부트 프로젝트에 빗대어 이해하는 AOP

 

요즘 타임리프로 프로젝트를 진행하는데, html 문서와 AOP가 완전 같지는 않지만 비슷한 점이 있다. 이해의 측면에서 한 번 읽어보면 좋을 것 같다.

 

<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head th:replace="fragment/common :: head('HOME')">

</head>
<body class="sb-nav-fixed" id="navFix">
<th:block th:replace = "fragment/common :: menu('home')"></th:block>
<div id="layoutSidenav">
    <div th:replace = "fragment/common :: side('side')"></div>
    <div id="layoutSidenav_content">

        <!-- 메인 페이지 맵 화면 -->
        <div th:replace ="mainMap/map_wrap :: map_wrap('map_wrap')"></div>

        <!--모임생성 게시판 모달, 채팅방 이동-->
        <div th:replace ="board/modal_board :: boardModal('boardModal')"></div>
        <div th:replace ="board/modal_board :: boardDetailModal('boardDetailModal')"></div>
        <div th:replace ="board/modal_board :: chatRoomModal('chatRoomModal')"></div>
        <footer th:replace = "fragment/common :: footer('footer')"></footer>
    </div>
</div>

<script src="js/modal-chat.js"></script>
<script src="js/main-map.js"></script>
<script src="js/modal-board.js"></script>
<script th:inline="javascript" src="js/modal-category.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>

</body>

</html>

 

이런 식으로 fragment 들을 쓰는 것이 생각났다. 그렇지만, 여기서는 직접 코드를 쳐야 그 fragment를 대체할 수 있는데, AOP는 어노테이션 하나로 기능을 그 클래스에 주입할 수 있는 점이 다르다.

 

중복을 줄이고 재사용하는 측면에서 타임리프의 fragment와 닮아있는 점이 있는 것 같다.

 

 

5. 결론(AOP란?)

 

중복을 줄이고, 핵심 비즈니스 로직에만 집중하게 하는 스프링 프로젝트의 모델이다.

 

치킨 튀기는 것은 조리장이, 치킨 박스 포장과 배달은 전문 알바생이, 닭 잡는 것은 하림이 알아서 하면 될 일이다...

조리장님이 치킨 박스 포장까지 하면 닭이 오버쿠킹 될 수도 있으니까....

 

 

 

 

 

 

<참고>

https://jojoldu.tistory.com/71
https://www.youtube.com/watch?v=WQR_VQnz7Yg

 

728x90

댓글