스프링 AOP는 프록시 기반의 AOP 구현 방식을 사용합니다. 이때 프록시란, 기존의 객체를 감싸서 접근을 제어하는 래퍼 객체를 의미합니다. 이러한 프록시 객체를 통해 AOP의 횡단 관심사를 구현합니다.
스프링에서는 프록시 객체를 생성하는 데에 JDK의 동적 프록시와 CGLIB(Code Generation Library)을 사용합니다. JDK의 동적 프록시는 인터페이스를 구현한 클래스에 대해서만 프록시 객체를 생성할 수 있습니다. 따라서 인터페이스를 구현한 클래스에 대해서만 적용 가능합니다. 반면에 CGLIB은 클래스의 바이트 코드를 조작하여 프록시 객체를 생성합니다. 이를 통해 클래스에 대해서도 프록시 객체를 생성할 수 있습니다.
스프링에서 AOP를 적용하면, 프록시 객체를 생성하여 대상 객체의 메소드를 호출하면서 AOP의 횡단 관심사를 적용합니다. 이를 통해 기존의 코드 변경 없이도 AOP를 적용할 수 있습니다.
스프링 AOP에서 프록시의 역할은 다음과 같습니다.
스프링에서 AOP를 적용하면, 프록시 객체를 생성하여 대상 객체의 메소드를 호출하면서 AOP의 횡단 관심사를 구현합니다. 이를 통해 기존의 코드 변경 없이도 AOP를 적용할 수 있습니다.
// Pointcut에 의해 필터링된 경로로 들어오는 경우 메서드 호출 전에 적용
@Before("cut()")
public void beforeParameterLog(JoinPoint joinPoint) {
// 메서드 정보 받아오기
Method method = getMethod(joinPoint);
log.info("======= method name = {} =======", method.getName());
// 파라미터 받아오기
Object[] args = joinPoint.getArgs();
if (args.length <= 0) log.info("no parameter");
for (Object arg : args) {
log.info("parameter type = {}", arg.getClass().getSimpleName());
log.info("parameter value = {}", arg);
}
}
// Poincut에 의해 필터링된 경로로 들어오는 경우 메서드 리턴 후에 적용
@AfterReturning(value = "cut()", returning = "returnObj")
public void afterReturnLog(JoinPoint joinPoint, Object returnObj) {
// 메서드 정보 받아오기
Method method = getMethod(joinPoint);
log.info("======= method name = {} =======", method.getName());
if (returnObj != null) {
log.info("return type = {}", returnObj.getClass().getSimpleName());
log.info("return value = {}", returnObj);
}
}
// JoinPoint로 메서드 정보 가져오기
private Method getMethod(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
return signature.getMethod();
}