핵심 기능과 부가 기능
애플리케이션 로직은 크게 핵심 기능
과 부가 기능
으로 나눌 수 있다.핵심 기능
이라 함은 객체가 가지고 있는 비즈니스로직으로 볼 수 있다. 만약 계산을 해주는 Calculator 라는 객체가 있다고 가정하면, Calcualtor의 핵심 기능은 사칙연산 등을 의미한다.부가 기능
은 핵심 기능을 보조하기 위한 기능이다. 단독으로 사용되지 않으며 핵심기능과 함께 사용된다. 예를 들면 메소드 실행 속도를 나타내는 로그, 트랜잭션 기능, 보안 기능 등등이 된다.
핵심 기능에 부가 기능을 추가해보자
@Slf4j
public class Calcualtor {
public int add(int x, int y) {
// 핵심 기능
return x + y;
}
public int sub(int x, int y) {
// 핵심 기능
return x - y;
}
}
Calculator 객체의 메소드별 실행속도를 측정하는 부가 기능
을 추가해보자.
@Slf4j
public class Calcualtor {
public int add(int x, int y) {
// 부가 기능
long startTime = System.currentTimeMillis();
// 핵심 기능
int result = x + y;
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("실행시간 : {}", resultTime);
return result;
}
public int sub(int x, int y) {
// 부가 기능
long startTime = System.currentTimeMillis();
// 핵심 기능
int result = x - y;
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("실행시간 : {}", resultTime);
return result;
}
}
부가 기능을 추가 후 코드를 보니 문제점이 몇 가지 보인다.
- 부가 기능을 적용할 때 중복 코드들이 여러개 생기게 된다. (부가 기능이 여러 곳에 쓰인다면 더욱더 심해진다.)
- 부가 기능을 변경할 때 중복된 코드들을 모두 수정해주어야 한다.
- 핵심 기능(비즈니스 핵심 로직)과 부가 기능(비즈니스와 상관 없는 로직)이 뒤엉켜 있다.
Calculator 객체에만 부가 기능을 적용하면 그나마 낫다. 하지만 xxxController, xxxService, xxxRepository에 해당하는 모든 메소드의 실행속도를 로그로 남기는 니즈가 있다면 어떻게 될까? 복붙 신공으로도 절레절레..
소프트웨어 개발에서 변경 지점은 하나가 될 수 있도록 잘 모듈화 해야 한다. 하지만 부가 기능처럼 특정 로직을 애플리케이션 전반에 적용하는 문제는 일반적인 OOP 방식으로는 해결이 어렵다.
AOP - 애스펙트
그리하여 나온 것이 AOP 라는 개념이다. 핵심 기능과 부가 기능을 분리하고 하고 부가 기능을 한 곳에서 관리하도록 하였다.
AOP(Aspect-Oriented Programming)는 OOP를 보완하는 수단으로 나왔다. 이름 그대로 해석해보면 관점 지향 프로그래밍으로 애플리케이션을 바라보는 관점을 하나의 기능에서 횡단 관심사(cross-cutting concerns, 흩어진 관심사라고도 한다.) 관점으로 보는 것 이다. (여기서 횡단 관심사는 부가 기능을 뜻함) AOP를 사용하면 횡단 관심사를 깔끔하게 처리하기 어려운 OOP의 부족한 부분을 보조할 수 있다.
Aspect = 부가 기능 + 부가 기능을 적용할 위치
- 메소드 실행 시간을 찍는 로그(부가기능)를 xxxController(위치)에 적용해라.
스프링이 제공하는 어드바이저(Advisor)도 어드바이스(부가기능) + 포인트 컷(적용 대상)을 가지고 있어 하나의 애스펙트라고 보면 된다.
AOP 적용 전
AOP 적용 후
- 산재되어 있는 횡단 관심사들을 별도의 Aspect로 모아 관리한다.
- Aspect에는 부가 기능 적용 대상의 정보가 있으며, 적용 대상에 부합한다면 부가 기능이 실행된다.
AspectJ 프레임워크
- AOP의 대표적인 구현으로 AspectJ 프레임워크가 있음
- 스프링도 AOP를 지원함
- AspectJ 문법 차용
- AspectJ 가 제공하는 방대한 기능 중 일부만 지원 (하지만 개발자가 쓰기엔 충분)
따라서 AspectJ 프레임워크를 깊이 공부할 필요는 없고 스프링 AOP를 학습하는게 좋아 보인다.
AOP 적용 방식
AOP를 사용할 때 부가 기능 로직은 어떤 방식으로 실제 로직에 추가될까?
3 가지 방식이 존재한다.
- 컴파일 시점
- 클래스 로딩 시점
- 런타임 시점(프록시 생성)
java 실행 프로세스를 참고하면 정확히 어느 시점에서 weaving이 일어나는지 파악하기 쉽다.
- weaving - target에 부가기능(advice)를 삽입하는 과정
컴파일 시점
- AspectJ가 제공하는 특별한 컴파일러를 사용하여
.java → .class
로 변환되는 시점에 부가 기능 로직이 추가된다. - AspectJ 컴파일러가 Aspect를 확인해서 해당 클래스가 적용 대상이면 부가 기능 로직을 적용한다.
→ 특별한 컴파일러도 필요하고 복잡
클래스 로딩 시점
.class
파일을 JVM에 로딩할 때 파일을 조작하여 부가 기능 로직을 추가한다.- Java Instrumentation - 수 많은 모니터링 툴들이 이 방식을 사용
→ 자바를 실행할 때 특별한 옵션(java -javaagent
)을 통해 별도 에이전트(바이트 코드 제어)를 지정해야 하며, 번거롭고 운영하기 어려움
런타임 시점
- 실제 대상 코드는 그대로 유지되고, 프록시를 통해 부가 기능이 적용된다. (스프링 AOP 방식)
AOP 적용 위치
- 적용 가능 지점 : 생성자, 필드 값 접근, static 메서드 접근, 메서드 실행
AspectJ
를 사용하여 컴파일/클래스로더 시점에 적용하는 AOP는 바이트코드를 실제 조작하기 때문에 해당 기능을모든 지점
에 사용할 수 있다.스프링 AOP
는메서드 실행 지점
에만 적용할 수 있다.- 프록시는 메서드 오버라이딩 개념으로 동작하기 때문에 생성자나 static 메서드, 필드 값 접근시에는 적용될 수 없다.
AOP 용어 정리
- 조인 포인트(Joint point)
- 어드바이스가 적용될 수 있는 모든 위치를 뜻한다.
스프링 AOP
는 프록시 방식을 사용하므로 조인 포인트는 항상메소드 실행 지점
이다.
- 포인트컷(Pointcut)
- 조인 포인트 중 어드바이스가 적용될 위치를 선별하는 기능(어디에 적용 될 것인지?)
- AspectJ 표현식을 사용해서 지정
- 타겟(Target)
- 어드바이스를 받는 객체이며 포인트 컷으로 결정
- 어드바이스(Advice)
- 부가 기능
- Around, Before, After 와 같은 다양한 종류의 어드바이스가 존재
- 애스펙트(Aspect)
- 어드 바이스 + 포인트컷을 모듈화한 것 (@Aspect)
- 어드바이저(Advisor)
- Advice + Pointcut 으로 구성 (Spring AOP 에서만 사용되는 용어)
- 위빙(Weaving)
포인트컷
으로 결정한타겟
의조인포인트
에어드바이스
를 적용하는 것- 핵심 기능 코드에 영향을 주지 않고 부가 기능을 추가
- AOP 프록시
- AOP 기능을 구현하기 위해 만든 프록시 객체
- in spring, JDK 동적 프록시 / CGLIB 프록시
참고) 스프링 핵심 원리 - 고급편 (김영한님) https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B3%A0%EA%B8%89%ED%8E%B8/dashboard
'프로그래밍 노트 > SPRING' 카테고리의 다른 글
[Spring] @Aspect AOP (0) | 2022.10.11 |
---|---|
[Spring] 빈 후처리기 (feat. proxy, advisor) (0) | 2022.10.11 |
[Spring] 프록시팩토리_2 (feat. Advisor) (0) | 2022.09.30 |
[Spring] 프록시팩토리_1 (feat. Advice) (0) | 2022.09.28 |
[Spring] 동적 프록시 기술(feat. 리플렉션) (0) | 2022.09.27 |