반응형
이번에는 Spring Boot에서 AOP(Aspect-Oriented Programming)를 활용해 코드의 중복을 제거하고 관심사 분리를 구현하는 방법을 알아보겠습니다.
1. AOP란 무엇인가?
AOP는 관심사 분리(Separation of Concerns)를 통해 핵심 비즈니스 로직과 부가적인 기능(로깅, 트랜잭션, 보안 등)을 분리하는 프로그래밍 기법입니다.
Spring AOP는 프록시 기반으로 동작하며, 다음과 같은 핵심 개념을 포함합니다.
- Aspect: 공통적으로 적용할 부가 기능
- Join Point: Aspect를 적용할 수 있는 지점 (메서드 호출 등)
- Advice: 특정 시점에서 실행되는 코드 (Before, After, Around 등)
- Pointcut: Aspect를 적용할 Join Point를 선택하는 표현식
2. 프로젝트에 AOP 추가
(1) 의존성 추가
pom.xml에 AOP 의존성을 추가합니다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Spring Boot Starter에는 기본적으로 포함되어 있는 경우가 많습니다.
3. AOP 구현하기
(1) Aspect 클래스 작성
@Aspect 어노테이션을 사용해 Aspect를 정의합니다.
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 1. 메서드 실행 전 실행
@Before("execution(* com.example.service.*.*(..))")
public void logBefore() {
System.out.println("메서드 실행 전: 로깅 시작");
}
// 2. 메서드 실행 후 결과 반환 시 실행
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void logAfterReturning(Object result) {
System.out.println("메서드 실행 후: 반환 값 - " + result);
}
// 3. 메서드 실행 중 예외 발생 시 실행
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "error")
public void logAfterThrowing(Throwable error) {
System.out.println("메서드 실행 중 예외 발생: " + error.getMessage());
}
// 4. 메서드 실행 전후에 로직을 삽입 (Around)
@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("메서드 실행 전: " + joinPoint.getSignature());
Object result = joinPoint.proceed();
System.out.println("메서드 실행 후: " + joinPoint.getSignature());
return result;
}
}
(2) Pointcut 표현식
Spring AOP는 execution을 사용해 특정 메서드나 클래스에 대해 Pointcut을 정의합니다.
- execution(* com.example.service.*.*(..))
- com.example.service 패키지의 모든 클래스와 모든 메서드에 적용
- execution(* com.example.service.UserService.getUser(..))
- UserService 클래스의 getUser 메서드에만 적용
- execution(public * *(..))
- 모든 public 메서드에 적용
4. AOP를 활용한 예제
(1) 서비스 클래스 생성
import org.springframework.stereotype.Service;
@Service
public class UserService {
public String getUser(String username) {
System.out.println("사용자 정보를 조회 중...");
return "사용자: " + username;
}
public void updateUser(String username) {
System.out.println("사용자 정보를 업데이트 중...");
}
}
(2) 컨트롤러 작성
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/user")
public String getUser() {
return userService.getUser("john");
}
}
5. 실행 결과
(1) 메서드 실행 로그
/user 엔드포인트 호출 시 아래와 같은 로그가 출력됩니다.
메서드 실행 전: 로깅 시작
사용자 정보를 조회 중...
메서드 실행 후: 반환 값 - 사용자: john
(2) 예외 처리
userService.getUser()에서 예외가 발생하면 @AfterThrowing이 실행됩니다.
6. AOP 적용의 장점
- 코드 중복 제거
로깅, 보안, 트랜잭션 처리와 같은 공통 코드를 분리하여 핵심 비즈니스 로직에만 집중할 수 있습니다. - 유지보수성 향상
공통 기능을 한 곳에서 관리하므로 수정과 확장이 용이합니다. - 모듈화
관심사를 분리하여 각 기능을 독립적으로 관리할 수 있습니다.
반응형
'개발 > 전자정부프레임워크' 카테고리의 다른 글
Spring Boot에서 Pagination(페이징)과 Sorting(정렬) 구현하기 (0) | 2024.12.29 |
---|---|
Spring Boot에서 트랜잭션 관리(Transaction Management) 설정하기 (0) | 2024.12.29 |
Spring Boot에서 Security를 사용한 인증 및 권한 부여 (0) | 2024.12.29 |
Spring Boot에서 트랜잭션 관리하기 (3) | 2024.12.29 |
데이터베이스 연결 풀 설정과 HikariCP 사용 (0) | 2024.12.29 |