[F-Lab 모각코 챌린지 61일차] 초간단 AOP

부추·2023년 7월 31일
0

F-Lab 모각코 챌린지

목록 보기
61/66

AOP가 뭐죠.

AOP(Aspect Oriented Programming)이란,

아주 널리 쓰이는 정의를 인용하자면 로깅, 트랜잭션 등 어플리케이션의 메인 로직과는 크게 상관 없는 부가적인 기능, 즉 "횡단 관심사"를 분리하기 위해 고안해낸 프로그래밍 방식이다.
그림을 보자. 위에서 아래로 흐르는 화살표는 프로그램의 메인 로직이다. 무언가를 계산하거나, 예시는 송금으로 들었지만 무언가 외부 IP를 사용하는 일이라든가, DB에 접근하는 프로그램의 주요 로직이다. 이것들을 "종단 관심사"라고 부른다.

종단 관심사는 개발자가 프로그램을 작성하는 목적이며, 프로그램이 존재하는 이유이다. 종단 관심사를 수행하는 기능을 구현하기 위해 우리가 개발을 하는 것이다.


그러나 위에서 아래로 흐르는 화살표를 가로지르는 초록색 바를 보자. 계산 로직을 수행할 때 성능을 측정하거나, 외부 API를 사용할 때 정보를 기록할 때 로직 수행 전후로 로그를 남길 수 있다. 혹은 DB 접근시 ACID 원칙을 지키기 위해 트랜잭션 처리를 할 수도 있다. 그런데 이것이 프로그램의 목적이냐고 묻는다면 .. 아니라고 답하겠다. 프로그램을 수행하는데 필요한 일은 맞지만 프로그램의 주요 로직과는 크게 관련이 없다.


이렇게 주요 로직과 동떨어진 횡단 관심사이지만, 프로그램을 수행하는덴 필요한 기능이므로 코드엔 들어가 있어야 한다. 계산로직, 송금로직, DB저장로직에 각각 로깅 처리를 해본다고 생각해보자.

public void 계산로직() {
	logging();
    
    // 계산로직 ...
    
    logging();
}

public void 송금로직() {
	logging();
    
    // 송금로직 ...
    
    logging();
}

public void DB저장로직() {
	logging();
    
    // DB저장로직 ...
    
    logging();
}

어떤가? 이게 보기 좋고 우리가 지향해야하는 코드라고 생각하는가?! 아니다!

AOP는 위의 코드에서 중복적으로 등장하는 logging()과 같은 기능을 Aspect라는 기능으로 따로 분리하여, aspect 로직이 붙은 기능을 수행할 때 프록시를 이용해 해당 aspect 코드를 "weaving"할 수 있도록 구성한 프로그래밍 방법이다.


프록시를 이용한다는게 어떤 것일까?

MyClass.종단로직() 메소드에 @Transactional 어노테이션이 붙었다고 생각해보자. 클래스 외부에서 해당 메소드를 호출하면, 프록시 객체가 해당 호출을 인터셉트하여, MyClass의 종단로직()을 대신 호출하게 된다. 그림으로 표현하면 아래와 같다.

"transaction 처리" 부분에 존재하는 로직이 횡단 관심사이다.



public이외의 메서드는 AOP가 걸리지 않는다.

왜일까?

spring boot 1.4 버전 이후부터는 aspect code weaving을 위해 default로 CGLIB을 사용한다. 여기서 CGLIB이란, Code Generator Libray의 약자로, 클래스의 바이트 코드를 조작하여 프록시 객체를 생성해 주는 라이브러리이다. "스프링 부트는 aspect weaving을 위한 라이브러리로 CGLIB을 사용한다".. 정도로 보자.

CGLIB은 동적으로 상속을 통해 프록시를 생성한다. 상위 클래스를 상속받아서 하위 클래스에서 해당 메소드를 호출하는 식의 구조를 띄는 것이다. private 접근 제어자가 붙은 메소드는 하위 클래스에서 사용할 수 없다. 따라서 private 메소드는 프록시로 만들어지지 않는다.



같은 클래스내에서 트랜잭션이 걸린 메소드를 호출하면 트랜잭션이 작동하지 않는다.

저번에 올린 내부 transactional 글과 이어지는 내용인데, 앞서 설명을 위해 그렸던 그림을 다시 한 번 봐보자. 종단로직1()이 내부에서 종단로직2를 호출하는 상황이다.
오른쪽 아래의 주황색 왕복 화살표, 그러니까 종단로직() <--> 종단로직2() 사이에 transaction 처리 혹은 aspect 코드가 weaving할 틈이 보이지 않는다. 프록시 내부의 self-invocation으로, 메소드 호출을 proxy가 인터셉트하지 못해서 트랜잭션이 동작하지 않는다.


어떻게든 내부 메소드를 호출하면서 Aspect를 적용하고 싶다면 AspectJ를 쓰거나, AopContext를 이용하는 방법, 자기자신을 호출하는 방법 등이 있다고 하는데 해당 방법은 REFERENCE를 참고하자!


REFERENCE

https://tecoble.techcourse.co.kr/post/2022-11-07-transaction-aop-fact-and-misconception/

profile
부추튀김인지 부추전일지 모를 정도로 빠싹한 부추전을 먹을래

0개의 댓글