Thanks to
@ㅅㅈㅎ 님 덕분에 3-5 첫번째 문장의 오타를 수정했습니다. 감사합니다! (더 간편합니다다. ⇢ 더 간편합니다.)
@김성수 님 덕분에 3-2. Weaving의 오타를 수정했습니다. 감사합니다! (컴파일 전 weaving ⇢ 컴파일 후 weaving)
0. 번역본에 대한 설명
오역/의역/직역 다수 존재합니다. 기술 용어 혹은 명칭, 주요 컨셉을 의미하는 용어는 번역하지 않고 영문 그대로 유지했고 파란색 글씨로 강조했습니다.
본문 내용 외 내용 이해를 위한 추가 정보는 초록색 글씨로 작성했습니다.
원문 : https://www.baeldung.com/spring-aop-vs-aspectj
1. 들어가며
요즈음 여러 AOP 라이브러리는 아래 요건을 충족해야만 합니다.
- 자신의 현재 혹은 새 애플리케이션에 적합한지?
- 어느 부분에 AOP를 적용할 수 있는지?
- 얼마나 빠르게 자신의 애플리케이션에 적용할 수 있는지?
- 성능의 오버헤드는 어느 정도인지?
이 글에서는 위 요건에 대한 대답과 Java에서 가장 유명한 AOP 프레임워크인 Spring AOP와 AspectJ를 소개하도록 하겠습니다.
오버헤드 : 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간과 메모리.
예를 들어 A라는 처리를 단순하게 실행한다면 10초 걸리는데, 안전성을 고려하고 부가적인 B라는 처리를 추가한 결과 처리시간이 15초 걸렸다면, 오버헤드는 5초가 된다. 또한 이 처리 B를 개선해 B'라는 처리를 한 결과, 처리시간이 12초가 되었다면, 이 경우 오버헤드가 3초 단축되었다고 말한다.
2. AOP의 개념
시작하기 앞서, 용어와 핵심 개념에 대해 알아봅니다.
- Aspect - 애플리케이션 내 여러 군데에 흩어져있는 코드/기능이며, 실제 비즈니스 로직과는 다릅니다.(예를 들면, 트랜잭션 관리). 각 Aspect는 고유한 Cross-Cutting 기능에 초점을 맞추고 있습니다. 쉽게 말하면, 여러 객체에 공통적으로 적용되는 관심 사항을 Aspect라고 합니다.
- Joinpoint - 프로그램이 실행 중일 때 발생하는 메서드 실행, 생성자 호출, 필드 값 변경과 같은 특수한 지점을 의미합니다.
- Advice - 특정 Joinpoint의 Aspect에 의한 동작을 의미합니다. 다시 말해, 대상 객체의 Joinpoint에 Weaving되어 동작할 수 있는 코드를 의미합니다.
- Pointcut - Joinpoint의 정규 표현식. Joinpoint가 Pointcut에 일치할 때마다 해당 Pointcut에 관련된 Advice가 실행됩니다.
- Weaving - Aspect를 대상 객체에 연결시켜 관점지향 객체로 만드는 과정을 의미합니다. Advice를 비즈니스 로직 코드에 삽입 하는 것을 의미합니다.
Cross-Cutting-Concern : 횡단 관심사항. 로깅, 트랜잭션, 보안과 같이 다수의 비즈니스 로직에서 반복적으로 발생하는 부분을 의미합니다. 이러한 반복적으로 발생하는 코드/기능을 한데로 모아 공통적인 기능을 만들게 됩니다.
3. Spring AOP와 AspectJ
이제 Spring AOP와 AspectJ를 성능과 목적, Weaving, 내부 구조, Joinpoint, 간편성 등 여러 축을 가로질러 비교하도록 하겠습니다.
3-1. 성능과 목적
간단히 말해, Spring AOP와 AspectJ는 목적이 다릅니다.
Spring AOP는 개발자가 마주한 공통적인 문제를 해결하고자 Spring IoC를 통한 간단한 AOP 구현이 그 목적입니다.
완전한 AOP를 의도한 것이 아니며, Spring Container에 의해 관리되는 Beans에만 적용이 가능합니다.
반면, AspectJ는 완전한 AOP를 제공하는 것이 목적인 근원적인 AOP 기술입니다. 확실히 Spring AOP보다 강력하지만 복잡합니다. 하지만 AspectJ는 모든 객체에 적용이 가능하다는 점에 주목해주세요.
Spring IoC : 제어의 역전. 인스턴스의 생명주기를 개발자가 아닌 Spring Container가 관리하는 것을 의미합니다.
Spring Container : 인스턴스의 생명주기를 관리하고 생성된 인스턴스에 추가적인 기능 제공도 가능합니다.
3-2. Weaving
AspectJ와 Spring AOP 모두 그들의 동작과 성능에 영향을 주는 각기 다른 방식의 Weaving을 사용합니다.
AspectJ는 세가지 방식의 Weaving을 사용할 수 있습니다.
- 컴파일 시점 Weaving : AspectJ 컴파일러가 Aspect 코드와 애플리케이션의 소스 모두 입력받아 Weaving된 class 파일을 생성합니다.
- 컴파일 후 Weaving : 바이너리 Weaving으로도 알려져 있습니다. 이미 존재하는 class 파일과 jar 파일을 Weaving하기 위해 사용됩니다.
- 로드 시점 Weaving : 위 바이너리 Weaving과 유사하나 Weaving 시점이 class 파일이 JVM에 로드될때 까지 연기된다는 점이 다릅니다.
AspectJ에 대한 좀 더 자세한 정보는 이곳에서 확인 가능합니다.
AspectJ가 컴파일 시점과 로드 시점 Weaving을 사용하듯이, Spring AOP는 런타임 Weaving을 사용합니다.
런타임 Weaving은 Aspect가 대상 객체의 Proxy(JDK 동적 Proxy나 CGLIB Proxy)를 사용하는 애플리케이션의 실행 시에 Weaving됩니다.
Proxy : 대상 객체에 Advice가 적용된 후 생성된 객체를 의미하며, 비즈니스 로직을 구현할 객체에 직접 접근하지 않고 Proxy를 통해 접근합니다.
3-3. 내부 구조와 애플리케이션
Spring AOP는 Proxy 기반 AOP 프레임워크입니다. 이 말은 대상 객체에 Aspect를 적용하기 위해서 대상 객체의 Proxy를 생성한다는 것입니다.
이것은 두 가지 방식에 의해 이뤄집니다.
- JDK 동적 Proxy : Spring AOP에서 선호되는 방식입니다. 언제든지 대상 객체가 한 개의 인터페이스를 구현하면 JDK 동적 프록시를 사용할 수 있습니다.
- CGLIB Proxy : 대상 객체가 인터페이스를 구현하지 않는 경우 CGLIB 프록시를 사용할 수 있습니다.
Spring AOP의 Proxy 매커니즘은 공식 문서를 통해 자세하게 알아볼 수 있습니다.
반면에, AspectJ는 클래스들이 Aspect와 함께 바로 컴파일되기 때문에 런타임시에는 아무것도 하지 않습니다.
또한 Spring AOP와는 달리, 어떠한 디자인 패턴도 요구하지 않습니다. Aspect를 코드에 Weaving하기 위해, AspectJ compiler(ajc)라는 컴파일러를 도입합니다. 이 컴파일러를 통해 프로그램을 컴파일하고 작은 런타임 라이브러리를 추가해 동작시킵니다.
3-4. Joinpoint
3-3에서 Spring AOP는 Proxy 패턴을 기반으로 했다는 것을 알게되었습니다. 그 때문에 Java 클래스의 세분화와 Cross-Cutting Concerns의 적용이 필요합니다.
하지만 한계가 존재합니다. Cross-Cutting Concerns과 Aspect는 final 클래스에 적용할 수 없습니다. final 클래스는 오바라이드될 수 없고 런타임 예외를 초래할 수 있기 때문입니다.
이 한계는 static과 final 메서드에도 동일합니다. Spring Aspect는 그 메서드들이 오버라이드될 수 없기 때문에 적용될 수 없습니다.
이러한 한계 때문에 Spring AOP는 메서드 실행에만 Joinpoint를 지원합니다.
그러나, AspectJ는 런타임 이전에 실제 코드에 Cross-Cutting Concerns를 Weaving합니다. Spring AOP와는 달리, 클래스 세분화를 필요로 하지 않으며 그 덕분에 다른 많은 Joinpoint를 지원합니다. 아래는 Spring AOP와 AspectJ에서 지원하는 Joinpoint를 정리, 비교한 것입니다.
Joinpoint | Spring AOP | AspectJ |
메서드 호출 | X | O |
메서드 실행 | O | O |
생성자 호출 | X | O |
생성자 실행 | X | O |
Static 초기화 실행 | X | O |
객체 초기화 | X | O |
필드 참조 | X | O |
필드 값 변경 | X | O |
핸들러 실행 | X | O |
Advice 실행 | X | O |
Spring AOP에서 동일 클래스 내 메서드 호출을 대상으로 Aspect 적용이 지원하지 않는 것에 주목할 필요가 있습니다.
동일 클래스 내 다른 메서드를 호출할 때 Spring AOP에서 제공하는 Proxy 메서드가 호출되지 않기 때문입니다. 만약 기능적으로 이것이 필요하다면, 메서드를 각기 다른 Beans로 분리해야만 합니다. 아님 AspectJ를 쓰던지.
3-5. 간편성
Spring AOP는 구현시에 다른 외장 컴파일러를 필요로하지 않기 때문에 확실히 더 간편합니다. 런타임 Weaving을 사용하기 때문에 일반적인 구현에 완벽하게 부합합니다. 간단해 보이지만, Spring에 의해 관리되는 Beans와만 동작합니다.
그러나 AspectJ를 사용하기 위해선, AspectJ compiler(ajc)라는 컴파일러를 도입해야하고 모든 라이브러리들을 재 패키징해야합니다.(컴파일 전 Weaving이나 로드 시점 Weaving으로 바꾸더라도).
물론 이건 Spring AOP보다 복잡합니다. IDE나 빌드 툴에 AspectJ 자바 툴(컴파일러(ajc)나 디버거(ajdb)나 문서 생성기(ajdoc)나 프로그램 구조 브라우저(ajbrowser)같은)을 추가해야하기 때문입니다.
3-6. 성능
성능면에서, 컴파일 시점 Weaving은 런타임 Weaving에 비해 훨씬 빠릅니다. Spring AOP는 애플리케이션의 시작시에 생성된 Proxy들을 기반으로한 프레임워크이고, 성능에 악영향을 주는 훨씬 적은 수의 메서드만을 지원합니다.
반면에, AspectJ는 Aspect를 애플리케이션이 실행되기 전에 Weaving 하기 때문에 Spring AOP와는 달리 런타임시 과부하가 없습니다.
이러한 이유에서 이 밴치마킹은 AspectJ가 Spring AOP보다 8배에서 35배 가까이 빠른것을 증명해줍니다.
4. 요약
이 표는 Spring AOP와 AspectJ간의 주요 차이점을 요약해줍니다.
Spring AOP | AspectJ |
순수 Java로만으로도 구현됨 | 추가 도구(자바 프로그램)를 통해 구현됨. |
복잡한 과정이 필요 없음 | 로드 시점 Weaving을 사용하더라도 AspectJ compiler(ajc)가 필요함. |
런타임 Weaving만 가능함 | 런타임 Weaving이 불가능함. 컴파일 시점/컴파일 전/로드 시점 Weaving을 지원함 |
메서드 레벨의 Weaving만 지원함 | 필드, 메서드, 생성자, final클래스/메서드 등 다양하게 지원함 |
Spring Container에 의해 관리되는 빈즈에만 적용할 수 있음 | 모든 객체를 대상으로 적용 가능함 |
메서드 실행 Point cut만 지원함 | 모든 Point cut을 지원함 |
대상 객체의 Proxy가 생성되고 Aspect는 이러한 Proxy를 대상으로 적용됨 | Aspect는 애플리케이션이 실행되기 전에 코드에 바로 Weaving됨.(런타임 이전) |
AspectJ에 비해 훨씬 느리다 | Spring AOP에 비해 좋은 성능 |
배우고 적용하기 쉽다 | Spring AOP에 비해 복잡하다. |
'☕️ JAVA' 카테고리의 다른 글
Enum을 사용해보자 (0) | 2020.10.18 |
---|---|
WebSocketSession에서 HttpSession를 얻는 방법 (0) | 2020.09.10 |
이미지를 BLOB 형태로 DB에 저장하기 (5) | 2018.09.09 |
웹 서버와 웹 어플리케이션 서버의 차이 (1) | 2017.12.22 |
예외(Exception) - 잘못된 처리들 (0) | 2017.12.04 |