반응형
AOP (Aspect Oriented Programming)
OOP 개발을 하면 핵심 기능과 부가 기능이 나뉘는데, AOP는 부가 기능을 관점(Aspect)으로 정의하여, 핵심 기능에서 부가 기능을 분리하여 설계하고 구현할 수 있게 도와줍니다.
부가 기능은 핵심 기능을 도와주는 기능으로 모듈화 되어 핵심 기능과 분리되어 구현할 수 있습니다.
Class A {
method a() {
AAAA
business Logic..
BBBB
}
method b() {
AAAA
business Logic..
BBBB
}
}
Class B {
method c() {
AAAA
business Logic..
BBBB
}
}
핵심 기능을 하는 business Login / 부가 기능을 하는 AAAA, BBBB 코드
AAAA, BBBB 는 여기저기서 사용되고 흩어져 있기에, 코드 변경이 필요한 경우 하나씩 전부 수정해주어야 합니다.
AOP는 부가 기능을 하나의 모듈로 묶어 처리한다. (⇒ 여러 곳에서 사용되는 중복된 코드를 분리하여 개발한다.)
AAAA, BBBB 코드가 AOP에서 의미하는 Aspect
method a, b, c 는 각각 business Logic만을 갖게 하고,
겹치고 중복되는 부가 기능 코드는 한 곳에서 관리하는 것이 AOP입니다.
AOP 장점
- 여러 곳에서 사용될 만한 코드들을 한 곳에서 관리하여 유지보수 이점이 있습니다.
- 핵심 기능에 집중하여 설계하고 구현할 수 있습니다.
AOP 특징
프록시 패턴 기반
- Spring은 타겟 객체에 대한 프록시 객체를 만들어 제공합니다.
- Target을 감싸는 프록시는 Run Time에 생성됩니다.
- Proxy는 Advice를 타겟 객체에 적용하면서 생성되는 객체입니다.
- 클라이언트는 타겟 객체를 직접 호출하는 대신 프록시 객체를 통해 호출합니다. 이렇게 하면 프록시가 타겟 객체에 추가적인 기능을 제공하거나, 호출을 가로채고 advice를 적용할 수 있습니다.
⇒ 프록시 객체를 사용하는 이유 : 접근 제어 및 부가 기능(AOP)을 추가하기 위함입니다.
Intercept
- Proxy는 타겟 객체에 대한 호출을 가로챈 다음, Advice의 부가 기능 로직을 수행한 후에 타겟의 핵심 기능을 호출합니다. (전처리 advice)
- 타겟의 핵심 기능 로직 메서드를 호출한 후에 부가 기능을 수행함 (후처리 advice)
method JoinPoint
- Spring은 동적 프록시를 기반으로 AOP를 구현하므로 method Joinpoint만 지원합니다.
- 핵심 기능의 메서드가 호출되는 런타임 시점에만 부가 기능을 적용할 수 있습니다.
AOP 용어
- Target
- 핵심 기능을 담고 있는 메서드(모듈)
- 부가 기능을 부여할 대상
- Aspect
- 핵심 기능에 부가되어 의미를 갖는 모듈
- 부가 기능 모듈을 Aspect라 부름
- 부가될 기능을 정의한 Advice와 어디에 적용할지를 결정하는 PointCut을 함께 가지고 있음
- Advice
- 부가 기능을 담은 구현체
- Target Object에 종속되지 않음, 부가 기능에만 집중할 수 있음
- Aspect가 무엇을 언제 할지를 정의
- PointCut
- 부가 기능이 적용될 대상(method)을 선정하는 방법
- Advice를 적용할 JoinPoint를 선별하는 기능을 정의한 모듈
- joinpoint 중에서 부가 기능을 적용할 대상을 선택하는 필터 역할을 합니다.
- JoinPoint
- Advice가 적용될 수 있는 위치
- 타겟 객체가 구현한 모든 메서드는 조인 포인트가 됩니다.
- Proxy
- Target을 감싸서 타겟의 요청을 대신 받아주는 wrapping object
- 클라이언트에서 Target을 호출하게 되면, 타겟이 아닌 타겟을 감싸고 있는 프록시 객체가 호출됩니다.
- 타겟 메서드 실행 전에 전처리, 후처리를 실행합니다.
AOP 실습
1. @EnableAspectJAutoProxy 어노테이션 추가하기
@SpringBootApplication
@EnableAspectJAutoProxy
public class QuerydslApplication {
public static void main(String[] args) {
SpringApplication.run(QuerydslApplication.class, args);
}
}
2. AOP 로직 작성 (부가 기능을 정의하고 사용될 시점을 정의합니다.)
추가할 기능 : 비즈니스 로직의 실행 시간을 측정하는 기능 추가
@Aspect
@Component
public class LogAspect {
Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Around("@annotation(LogExecutionTime)")
public Object logging(ProceedingJoinPoint pjp) throws Throwable {
StopWatch sw = new StopWatch();
sw.start();
Object result = pjp.proceed();
sw.stop();
long executionTime = sw.getTotalTimeMillis();
String className = pjp.getTarget().getClass().getName();
String methodName = pjp.getSignature().getName();
String task = className + ". " + methodName;
logger.info("[EXECUTIONTIME] " + task + "-->" + executionTime + "(ms)");
return result;
}
}
- AOP 클래스 설정을 위해 @Aspect 어노테이션을 추가합니다.
- Spring Bean으로 등록하려면 @Component를 추가합니다.
- @Around : 메서드 실행 전 후, 실행 흐름 자체를 제어할 수 있습니다. 타겟 메서드의 실행 여부나 결과를 직접 제어할 수 있음
- https://ittrue.tistory.com/233
"execution(* com.example.service.*.*(..))"는 com.example.service 패키지에 속한 모든 클래스의 모든 메서드에 대해 이 로직을 적용합니다.
3. Annotation을 통해 Aspect 적용하기
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}
4. 적용할 Joinpoint에 어노테이션 추가하기
@LogExecutionTime
@GetMapping("/v1/product")
public List<ProductResponse> getProductList(
@Nullable @RequestParam("category") String category) {
return productService.getProductList(category);
}
참고자료
반응형
'Spring Framework > Spring' 카테고리의 다른 글
Spring Scope 어노테이션으로 빈 라이프사이클 이해하기 - prototype, request, session (4) | 2024.10.13 |
---|---|
스프링 FactoryBean: 생성자 주입과 필드 주입 시 프록시 객체의 동작 차이 (0) | 2024.10.12 |
[Spring] 스프링 FactoryBean 이해하기 - Custom Bean 생성방법 (2) | 2024.10.09 |
[Spring] Spring Batch Tasklet 작업 단위 이해하기 - StepContribution, ChunkContext (0) | 2024.10.07 |
[Spring] MessageSource, messages_en.properties 파일에서 작은 따옴표 및 특수 문자 처리 오류 해결 방법 (2) | 2024.10.03 |