💡 AOP(Aspect-Oriented Programming)는 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 모듈화하여 재사용할 수 있도록 지원하는 것입니다.
각각의 Service를 핵심적인 관점으로 보았을 때는 User와 Order의 공통된 요소가 없지만 부가적인 관점으로 보았을 때는 공통된 요소를 볼 수 있습니다.
부가적인 관점에서 바라보면 공통된 메서드를 확인할 수 있습니다.
기존에 OOP에서 바라보는 관점을 다르게 하여 부가기능적인 측면에서 보았을 때 공통된 요소를 추출 하자는 것입니다. 이때 공통된 부분을 잘라내는 것을 AOP를 크로스 컷팅(Cross-Cutting)이라고 부르기도 합니다.
OOP: 비지니스 로직의 모듈화
AOP: 인프라 혹은 부가기능의 모듈화
간단하게 한줄로 AOP를 정리해보자면 AOP는 공통된 기능을 모듈화하여 재사용하는 기법입니다.
OOP에선 공통된 기능을 재사용하는 방법으로 상속이나 위임을 사용합니다.
하지만 전체 애플리케이션에서 부가기능들을 상속이나 위임을 처리하기에는 깔끔한 모듈화가 어렵습니다.
그래서 등장한 것이 바로 AOP입니다.
AOP 적용 방식에는 3가지 방법이 있습니다.
proxy 패턴에서는 interface가 존재하고 Client는 이 interface 타입으로 Proxy 객체를 사용한다. Proxy 객체는 기존의 타겟 객체(Real Subject)를 참조한다. Proxy 객체와 기존의 타겟 객체의 타입은 같고, Proxy는 원래 할 일을 가지고 있는 Real Subject를 감싸서 Client의 요청을 처리한다.
이해하기 쉽게 Spring AOP를 적용하기 전과 적용한 후의 코드 예시를 보여드리겠습니다.
public class UserService {
public void addUser(User user) {
// 사용자 추가 로직
}
public void deleteUser(int userId) {
// 사용자 삭제 로직
}
}
public interface UserService {
void addUser(User user);
void deleteUser(int userId);
}
@Service
public class UserServiceImpl implements UserService {
@Override
public void addUser(User user) {
// 사용자 추가 로직
}
@Override
public void deleteUser(int userId) {
// 사용자 삭제 로직
}
}
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.UserService.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("메서드 실행 전 로깅 작업");
}
}
위의 예시에서 UserService 인터페이스와 그를 구현한 UserServiceImpl 클래스를 정의하였다. 그리고 AOP를 적용하기 위해 LoggingAspect 클래스를 작성하였다. LoggingAspect는 @Aspect 어노테이션을 사용하여 AOP 관련 설정을 하고, @Before 어노테이션을 사용하여 메서드 실행 전에 로깅 작업을 수행한다.
이렇게 Spring AOP를 적용하면 UserService의 메서드를 호출할 때마다 로깅 작업이 수행된다.