본문 바로가기

Spring

Spring AOP 주의할 점 (프록시의 주의할 점)

728x90

Spring에서 aop를 동작할 땐 프록시 방식으로 동작한다. 하지만 이 프록시를 사용할 때 주의할 점이 무엇인가 질문을 받았던 적이 있는데, 대답을 못했다.

그러고보니 나는 업무를 하면서 aop를 사실 잘 안쓰기도 했고, 개인적으로 사용할 때 그런걸 고려해본적이 없는데 그동안 aop를 제대로 활용하지 않아서 그런것이라고 생각된다.

 

그러면 질문의 답이 무엇일까? 사실 모른다. 하지만 구글링을 조금 해본 결과 스프링에서 aop를 타지 않는 케이스가 생길 수 있는데 아래와 같은 상황이다.

 

콘솔에 print만 하는 간단한 Service와 aop를 구현했다.

 

PrintTestService

@Service
public class PrintTestService {

	@AopTester
	public void logicA() {
		System.out.println("AAAAAAAAAAAAAAAAAAAAA");
		logicB();
	}
	
	@AopTester
	public void logicB() {
		System.out.println("BBBBBBBBBBBBBBBBBBBBB");
	}
}

콘솔 출력하는 기능밖에 없다. logicA에서 logicB를 호출하고 있고, 간단하게 임시로 만든 커스텀 어노테이션

@AopTester가 둘다 적용되어있어 둘다 aop가 적용된다는 것만 보면된다.

 

 

@AopTester 어노테이션

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AopTester {

}

 

AopTestAspect

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopTestAspect {
	private static final Logger log = LoggerFactory.getLogger(AopTestAspect.class);
	
	@Around("@annotation(com.zero.web.aop.AopTester)")
	public Object timeCheck(ProceedingJoinPoint joinPoint) throws Throwable {
		
		System.out.println("AOP Before");
		Object proceed = joinPoint.proceed();
		System.out.println("AOP After");
		
		return proceed;
	}
}

Aspect도 마찬가지로 콘솔에 출력하는 기능뿐이다.

 

사실 민망하게도 나는 이와 같은 상황을 맞이한적이 없는데, 구현하면서 생각해보니 이렇게 되면 둘다 aop를 타겠는데? 생각했다.

예상 출력
AOP Before
AAAAAAAAAAAAAAAAAAAAA
AOP Before
BBBBBBBBBBBBBBBBBBBBB
AOP After
AOP After

이런 형태로 출력되지 않을까 했는데 결과는 달랐다.

 

결과

AOP Before
AAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBB
AOP After

 

생각해보면 당연한 결과다. aop는 프록시를 기반으로 동작하는데 Service에서 내부의 다른 메서드를 호출할땐 생성된 프록시 객체의 메서드를 호출하는게 아니니까. 

PrintTestService프록시.logicB(); 이어야 AOP를 타는데
PrintTestService.logicB() 인 셈이라서 안탐  //정확히는 this.logicB()

 

 

지금까진 의도치 않게 이런 상황을 피했는데, 로그처리나 권한처리 같은 aop의 경우처럼 동일하게 둘다 aop처리가 되어야 하는 경우가 필요할 것이라고 생각한다.

 

그땐 구조를 바꿔보도록 하자

 

728x90