🌐 Aspect-Oriented Programming (AOP)
AOP는 관심사 분리를 목표로 하는 프로그래밍 패러다임입니다. 특히 로깅, 트랜잭션 관리, 보안과 같은 횡단 관심사(Cross-cutting concerns)를 비즈니스 로직에서 분리할 수 있도록 해줍니다. 비즈니스 로직과는 상관없는 코드가 곳곳에 중복해서 나타나는 문제를 해결해주기 때문에 유지보수성을 크게 향상시킬 수 있습니다. 이를 통해 비즈니스 로직은 본연의 역할에만 집중할 수 있게 되는 거죠.
🌟 AOP의 핵심 개념
- 횡단 관심사(Cross-Cutting Concern): 애플리케이션 전반에 걸쳐 사용되는 공통된 기능들. 예를 들어, 로깅, 트랜잭션 관리, 보안 처리 같은 것들이 이에 해당됩니다. 이들은 각 모듈에서 필요로 하지만, 해당 모듈의 핵심 기능은 아닙니다.
- Aspect: 횡단 관심사 로직을 모듈화한 것을 Aspect라고 부릅니다. 예를 들어, 트랜잭션 관리, 로깅 등을 각각의 Aspect로 만들 수 있습니다.
- Advice: Aspect가 언제, 어떻게 적용될지 정의하는 동작입니다. Before, After, Around와 같은 여러 타입이 존재합니다.
- Join Point: Aspect가 적용될 수 있는 지점을 의미합니다. 예를 들어, 메서드 호출이나 예외 처리 등이 이에 해당합니다.
- Pointcut: Join Point 중 실제로 Advice가 실행되는 지점을 선택하는 것입니다. AOP에서는 특정 메서드나 클래스에만 Aspect가 적용되도록 Pointcut을 정의합니다.
2. 🌐 AOP 설정 및 적용 방법
AOP를 적용하려면, 기본적으로 Spring이 AOP를 인식하고 관리할 수 있도록 설정이 필요합니다.
1) AOP 의존성 추가 (Maven 예시)
대부분의 Spring 프로젝트에서는 AOP 의존성이 기본적으로 포함되어 있지만, 만약 그렇지 않다면 다음과 같이 의존성을 추가해줘야 합니다:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2) AOP 기능 활성화
@EnableAspectJAutoProxy
어노테이션을 통해 Spring의 AOP 기능을 활성화할 수 있습니다. Spring Boot 프로젝트에서는 보통 Application 클래스에 이 어노테이션을 추가합니다:
@SpringBootApplication
@EnableAspectJAutoProxy // AOP 기능 활성화
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
3) @Aspect
로 AOP 적용하기
Aspect를 만들기 위해서는 @Aspect
어노테이션을 사용해 클래스를 정의하고, 해당 클래스를 Spring 컨텍스트에 등록해야 합니다. 일반적으로 @Component
나 @Bean
을 사용하여 Spring이 관리하는 Bean으로 등록합니다.
로깅을 위한 AOP 예시
다음은 메서드 호출 전에 로그를 남기는 Aspect를 정의한 예시입니다:
@Aspect
@Component // Spring Bean으로 등록
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("메서드 실행 전: " + joinPoint.getSignature().getName());
}
@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
System.out.println("메서드 실행 후: " + joinPoint.getSignature().getName());
}
@AfterThrowing("execution(* com.example.service.*.*(..))")
public void rollbackTransaction() {
// 트랜잭션 롤백 로직
System.out.println("트랜잭션 롤백");
}
}
이 코드에서는:
@Before
어노테이션을 통해 메서드 실행 전에 로그를 출력하는 Advice를 적용했고,@After
어노테이션으로 메서드가 끝난 후에도 로그를 출력하게 했습니다.@AfterThrowing
어노테이션으로 예외처리 시 로그를 출력하게 했습니다.
execution(* com.example.service.*.*(..))
는 Pointcut 표현식으로, com.example.service
패키지의 모든 클래스의 모든 메서드에 대해 AOP를 적용한다는 의미입니다.
4) 트랜잭션을 위한 AOP 예시
트랜잭션 관리도 AOP로 처리할 수 있습니다. 하지만 일반적으로는 Spring이 제공하는 @Transactional
어노테이션을 사용하는 것이 편리합니다.
@Service
public class OrderService {
@Transactional
public void placeOrder(Order order) {
// 주문 상태 확인
if (!order.isValid()) {
throw new IllegalStateException("주문 상태가 유효하지 않습니다.");
}
// 주문 처리 로직
orderRepository.save(order);
// 기타 비즈니스 로직
// 트랜잭션은 알아서 커밋됩니다.
}
}
이 코드에서 @Transactional
어노테이션을 사용하면, Spring이 내부적으로 AOP를 이용해 트랜잭션을 관리합니다. 비즈니스 로직이 정상적으로 완료되면 트랜잭션이 커밋되고, 예외가 발생하면 롤백됩니다.
3. 💡 정리
- AOP는 로깅, 트랜잭션 관리 같은 공통 기능을 비즈니스 로직과 분리하여 더 깔끔한 코드를 작성할 수 있게 해줍니다. 이를 통해 중복 코드를 제거하고, 유지보수가 쉬워집니다.
- Spring AOP는
@Aspect
,@Before
,@After
같은 어노테이션을 사용해 쉽게 적용할 수 있으며, AOP 기능을 활성화하려면@EnableAspectJAutoProxy
어노테이션을 추가해줘야 합니다. - 트랜잭션 관리는 보통
@Transactional
어노테이션을 사용하여 Spring에서 자동으로 처리할 수 있습니다.
'Java' 카테고리의 다른 글
[JAVA] Spring 돌아보기 Part.3 #JDBC #MyBatis #Multiple DataSources (4) | 2024.10.10 |
---|---|
[JAVA] Spring Boot Redis 캐시 사용법 (0) | 2024.09.20 |
[JAVA] Spring 돌아보기 Part.1 #IoC #DI #싱글톤 (0) | 2024.09.10 |
[JAVA] 객체 비교와 Integer 클래스 (0) | 2024.09.09 |
[JAVA] #Deque VS Queue #ArrayDeque VS LinkedList #Map (1) | 2024.09.06 |