AOP(Aspect-Oriented Programming)는 프로그래밍 패러다임 중 하나로, 핵심 비즈니스 로직과는 별개로 횡단 관심사(Cross-cutting Concerns)를 모듈화하고 재사용 가능한 방법으로 분리하는 것을 목표로 한다.
주요 개념
어드바이스(Advice)
: 실제로 수행되어야 할 작업을 정의한 코드 조각입니다. 예를 들면 메서드 실행 전/후에 수행되어야 할 작업 등입니다.타겟(Target)
: 어드바이스가 적용될 대상 객체 또는 메서드입니다.조인 포인트(Join Point)
: 타겟 객체 내에서 Advice가 적용될 수 있는 위치를 말합니다. 예를 들면 메서드 호출 시점, 필드 값 변경 시점 등입니다.포인트컷(Pointcut)
: 조인 포인트 중 일부만 선택하는 기준을 정의하는 것으로, 어느 Join Point에 Advice를 적용할지 결정합니다.위빙(Weaving)
: AOP 프레임워크가 컴파일 시간, 클래스 로딩 시간 또는 실행 시간에 Aspect와 Target 사이에 연결 작업을 수행하여 Aspect 코드가 적절한 위치에서 동작하도록 하는 과정입니다.
동작 원리 👉 컴파일 타임 / 클래스 로딩 타임 /런타임
런타임 방식은 애플리케이션이 이미 시작된 이후부터 동작하며, 프록시 객체를 생성하여 Advice 코드를 적용하는 방식입니다. 대부분의 AOP 프레임워크는 런타임 방식을 사용한다.
implementation 'org.springframework.boot:spring-boot-starter-aop' = 의존성 추가
@Aspect / @Component
-LoggingAspect
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.practice.service.Calculator.divide(..))")
public void beforeDivide(JoinPoint joinPoint) {
System.out.println("나눗셈 연산 시작");
Object[] args = joinPoint.getArgs();
System.out.println("나누는 수: " + args[0]);
System.out.println("나눠지는 수: " + args[1]);
}
@AfterReturning(pointcut = "execution(* com.example.practice.service.Calculator.divide(..))", returning = "result")
public void afterDivide(JoinPoint joinPoint, Object result) {
System.out.println("나눗셈 연산 종료");
System.out.println("결과: " + result);
}
}
@Before
: 대상 메서드 실행 전
("execution(* com.example.practice.service.Calculator.divide(..))")
: 해당 메서드의 위치와 포인트컷 표현식 사용
따라서, joinPoint.getArgs()를 호출하면 divide 메서드의 매개변수 int a와 int b의 값이 Object 배열로 반환된다. 배열의 첫 번째 원소(args[0])는 int a의 값이고, 두 번째 원소(args[1])는 int b의 값
- JoinPoint 자체는 매개변수를 나타내지 않지만, 그를 통해 메서드의 매개변수에 접근할 수 있다.
@Service
-Calculator
@Service
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int divide(int a, int b) {
return a / b;
}
}
@SpringBootApplication
@EnableAspectJAutoProxy
-PracticeApplication
@SpringBootApplication
@EnableAspectJAutoProxy
public class PracticeApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(PracticeApplication.class, args);
Calculator calculator = context.getBean(Calculator.class);
int result = calculator.divide(10, 2);
System.out.println("결과: " + result);
}
}