Spring AOP 란 무엇일까?
🔍 Spring AOP란 무엇일까?
Spring AOP는 스프링에서 제공하는 강력한 기능 중 하나로 "관점 지향 프로그래밍"을 지원하는 기술입니다.
이때 관점 지향 프로그래밍이란 핵심로직과 부가기능을 분리해 애플리케이션 전체에 걸쳐 사용되는 부가 기능을 모듈화해 기능을 재사용 할 수 있도록 도와 프로젝트 구조를 바라보는 관점을 바꿔보자라는 의미를 가지고 있습니다.
주로 로깅, 보안, 트랜잭션 관리와 같은 공통적인 관심사를 모듈화해 코드의 중복을 줄이고 유지 보수성을 향상시키는데 도움을 줍니다.
Spring AOP를 자세히 알아보기 전 용어 정리부터 해봅시다.
포인트컷(Point Cut) : 어디바이스가 적용될 위치를 선별하는 기능
어드바이스(Advice) : 부가 기능 로직
어드바이저(Advisor) : 1개의 포인트컷과 1개의 어드바이스로 구성
조인 포인트(Join Point) : 어드바이스가 적용될 수 있는 위치
에스펙트(Aspect) : 어드바이스와 포인트컷을 모듈화 한 것
그렇다면 Spring 에서는 어떻게 어드바이저를 이용해 프록시를 만들까?
스프링에서 프록시를 적용하려면 어드바이저(Advisor)를 만들어 스프링 빈으로 등록하면 됩니다.
나머진느 자동 프록시 생성기가 모두 알아서 처리해줍니다. 자동 프록시 생성기는 스프링 빈으로 등록된 어드바이저를 찾고, 스프링 빈으로 프록시를 적용해줍니다.
스프링은 @Aspect 애노테이션으로 쉽게 포인트컷과 어드바이스로 구성되어 있는 어드바이저 생성을 지원합니다.
어드바이저를 기반으로 프록시를 생성하는 과정
1. 스프링이 모든 빈을 생성한다. (@Bean, 컴포넌트 스캔)
2. 스프링 빈으로 등록된 Advisor 를 스프링 컨테이너에서 모두 조회한다.
3. @Aspect 로 등록된 Advisor를 모두 조회한다.
4. 조회한 Advisor 를 확인하며 프록시를 생성할 수 있는지 확인한다.
5. 만약 Advisor 를 확인했는데 적용 가능한 객체이면 프록시를 생성한다.
주로 실무에서는 Advisor를 직접 스프링 빈으로 등록하는게 아닌 @Aspect 애노테이션을 사용해 프록시를 생성한다고 합니다.
Spring AOP 사용법
긴말 필요 없이 코드로 바로 Spring 에서 AOP 를 사용하는 방법을 알아봅시다.
🎯 OrderRepository
package hello.aop.order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
@Slf4j
@Repository
public class OrderRepository {
public String save(String itemId) {
log.info("[orderRepository] 실행");
return "ok";
}
}
🎯 OrderService
package hello.aop.order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
public void orderItem(String itemId) {
log.info("[orderService] 실행");
orderRepository.save(itemId);
}
}
자 여기까진 기본적인 Repository 계층과 Service 계층에 대한 클래스 구현 코드입니다.
이제 Spring AOP 를 적용해 다양한 클래스에서 프록시를 만들어 적용해 봅시다!
🎯 Aspect
@Aspect 애노테이션을 이용한 가장 기본적인 에스팩트 사용법 입니다.
에스팩트로 만들고 싶은 클래스에 @Aspect 애노테이션을 사용해 에스펙트임을 지정해줍니다.
@Around 애노테이션을 사용해 어디에 어드바이스 기능을 추가한 프록시를 만들 것인지 포인트컷을 지정해 줍니다.
"execution(* hello.aop.order..*(..))" 와 같은 표현식은 AspectJ Pointcut expression 즉, 에스펙트 J 가 제공하는 포인트컷 표현식입니다. 표현식에 대해선 기능이 많고 복잡하니 다음 포스팅에서 설명하겠습니다.
package hello.aop.order.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Slf4j
@Aspect
public class Aspect {
@Around("execution(* hello.aop.order..*(..))")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
}
자! 이제 에스팩트를 만들었고 만든 에스팩트를 스프링 빈으로 등록하면 @Around의 포인트 컷을 참고해 어떤 스프링 빈에 어드바이스를 적용할지는 스프링이 알아서 처리해 줍니다.
🎯 테스트
package hello.aop;
import hello.aop.order.OrderRepository;
import hello.aop.order.OrderService;
import hello.aop.order.aop.AspectV1;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
@Slf4j
@Import(AspectV1.class)
@SpringBootTest
public class AopTest {
@Autowired
OrderService orderService;
@Autowired
OrderRepository orderRepository;
@Test
void aopInfo() {
log.info("isAopProxy, orderService = {}", AopUtils.isAopProxy(orderService));
log.info("isAopProxy, orderRepository = {}", AopUtils.isAopProxy(orderRepository));
}
@Test
void success() {
orderService.orderItem("itemA");
}
}
출력 결과
2024-03-20T16:43:11.161+09:00 INFO 10364 --- [aop] [ main] hello.aop.order.aop.AspectV1 : [log] void hello.aop.order.OrderService.orderItem(String)
2024-03-20T16:43:11.163+09:00 INFO 10364 --- [aop] [ main] hello.aop.order.OrderService : [orderService] 실행
2024-03-20T16:43:11.163+09:00 INFO 10364 --- [aop] [ main] hello.aop.order.aop.AspectV1 : [log] String hello.aop.order.OrderRepository.save(String)
2024-03-20T16:43:11.163+09:00 INFO 10364 --- [aop] [ main] hello.aop.order.OrderRepository : [orderRepository] 실행
출력된 내용을 보면 orderService 와 orderRepository 에 있는 메서드가 호출되기 전 에스팩트에서 적용한 어드바이스 즉, 로그 출력기가 잘 적용된 것을 확인해 볼 수 있습니다.
총 정리
Spring AOP 는 로깅, 트랜잭션 관리 와 같은 부가 기능을 모듈화해 코드의 중복과 유지보수성을 향상 시킬 수 있습니다.
Spring AOP 는 에스팩트(포인트컷 + 어드바이스) 를 @Aspect 애노테이션을 이용해 스프링 빈에 등록하고 스프링 컨테이너에서 등록된 에스펙트 빈들을 모두 조회해 포인트 컷으로 어떤 스프링 빈에 적용해 프록시를 만들지 판단하고 그 프록시에 어드바이스를 적용하는 흐름을 가집니다.
'Spring > Spring' 카테고리의 다른 글
[Spring] 연관관계를 포함한 객체 MapStruct 사용법 (0) | 2024.04.17 |
---|---|
[Spring] Spring Security + OAuth2.0 + Jwt 예제 구현 (0) | 2024.03.29 |
[Spring] Spring Security 와 Jwt 를 이용한 회원가입, 로그인 구현 (0) | 2024.03.24 |
[Spring] Jwt 와 OAuth2.0 간단하게 알아보기 (0) | 2024.03.22 |
[Spring] JDK 동적 프록시을 알아보자 (0) | 2024.03.13 |