본문 바로가기
Java/[스프링 5 프로그래밍 입문]

[Spring] AOP 프로그래밍(3) - 스프링에서의 프록시 생성 방식

2021. 9. 1.
반응형

AOP는 여러 객체에 공통으로 적용할 수 있는 기능을 분리해서 재사용성을 높여주는 프로그래밍 기법이다. 스프링에서는 프록시 객체를 자동으로 만들어 공통 기능을 삽입하는데, 이때 프록시 객체를 어떻게 만드는지 살펴보자.

 

스프링에서 프록시가 생성되는 방식

스프링은 AOP를 위한 프록시 객체를 생성할 때 빈 객체가 인터페이스를 상속한다면 해당 인터페이스를 이용해서 프록시를 생성한다. 아래 그림처럼 프록시와 빈 대상 클래스가 하나의 인터페이스를 상속받는 관계인 것이다.

인터페이스를-상속하는-빈의-프록시
인터페이스와 프록시

Calculator cal = ctx.getBean("calculator", Calculator.class);    // 정상 동작
RecCalculator cal = ctx.getBean("calculator", RecCalculator.class);    // 익셉션 발생

따라서 프록시를 RecCalculator 클래스 타입으로 지정하면 익셉션이 발생하게 된다. 인터페이스가 아닌 클래스를 이용해서 프록시를 생성하고 싶다면 다음과 같이 @EnableAspectJAutoProxy 애노테이션의 proxyTargetClass 속성을 true로 설정하면 된다.

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppCtx { 
	...
}

AOP 관련 애노테이션 설정

@Pointcut 애노테이션의 execution 속성 표현식

Aspect를 적용할 위치를 지정할 때 @Pointcut 애노테이션에 execution 속성을 이용한다. 이때 표현식 규칙은 아래와 같다.

execution(수식어패턴? 리턴타입패턴 클래스이름패턴?메서드이름패턴(파라미터패턴))

수식어패턴은 생략 가능하며 public, protected 등이 오는데 스프링 AOP는 public 메서드에만 적용할 수 있으므로 public만 의미가 있다. 각 패턴은 *을 이용하여 모든 값을 표현할 수 있고 ..을 이용하여 0개 이상이라는 표현을 할 수 있다.

@Pointcut("execution(public * chap07..*(..))")

이전 포스트에서 작성한 표현식을 해석해보자. chap07 패키지 및 하위 패키지에 있으며, 파라미터가 0개 이상인 메서드를 호출한다는 의미이다.

 

Aspect의 순서 설정

한 Pointcut 에는 여러 Advice를 적용할 수도 있다. 즉, 하나의 메서드에 여러 개의 공통 기능이 적용되는 것이다. 이 경우 어떤 Aspect가 먼저 적용될지는 스프링이나 자바 버전에 따라 달라질 수 있으므로 적용 순서가 중요하다면 직접 순서를 지정해야 한다. 이때 @Order 애노테이션을 사용한다. @Aspect 애노테이션과 함께 @Order 애노테이션을 클래스에 붙이면 지정한 값에 따라 적용 순서가 결정된다.

@Aspect
@Order(1)
public class ExeTimeAspect {
	...
}
@Aspect
@Order(2)
public class CacheAspect {
	...
}

 

@Around의 Pointcut 설정 및 @Pointcut의 재사용

@Around의 Pointcut 설정

@Around 애노테이션에 execution 명시자를 직접 지정할 수 있다. 예시 코드는 아래와 같다.

@Aspect
public class ExeTimeAspect {
	@Around("execution(public * chap07..*(..))")
	public Object measure(ProceedingJoinPoint joinPoint) throws Throwable{
		...
	}
}

 

@Pointcut의 재사용

같은 Pointcut을 여러 Advice가 함께 사용한다면 정의된 Pointcut을 재사용할 수 있다. 이전 포스트의 ExeTimeAspect 클래스에서 Pointcut인 publicTarget() 메서드를 정의한 뒤 Around에서 호출해 사용한 것처럼, 정의된 Pointcut을 원하는 곳에서 호출하여 사용하면 된다.

여러 Aspect에서 공통으로 사용하는 Pointcut이 있다면 별도 클래스에 Pointcut을 정의하고 각 Aspect 클래스에서 호출하여 사용하도록 구성하면 관리가 편해진다. 아래 코드는 Pointcut 재사용의 예시이다. @Pointcut을 설정한 CommonPointcut 클래스는 빈으로 등록할 필요가 없다.

public class CommonPointcut {
	@Pointcut("execution(public * chap07..*(..))")
	public void commonTarget() {
	}
}
@Aspect
public class ExeTimeAspect {
	@Around("CommonPointcut.commonTarget()")
	public Object measure(ProceedingJoinPoint joinPoint) throws Throwable{
		...
	}
}
@Aspect
public class CacheAspect {
	...
	@Around("CommonPointcut.commonTarget()")
	public Object execute(ProceedingJoinPoint joinPoint) throws Throwable{
		...
	}
}

 

 

 

참고 서적: <초보 웹 개발자를 위한 스프링 5 프로그래밍 입문>

 

초보 웹 개발자를 위한 스프링5 프로그래밍 입문

COUPANG

www.coupang.com

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.


Spring Framework 시리즈

  1. 스프링 프로젝트 시작하기 (Maven)
  2. 스프링 컨테이너(Container) 의미
  3. Dependency, DI, Assembler (의존, 의존 주입, 주입기) 개념 정리
  4. 스프링에서의 의존 주입(DI)의 의미와 사용법
  5. 스프링 애노테이션을 사용한 의존 주입(DI)
  6. 의존 자동 주입(1) - @Autowired 애노테이션
  7. 의존 자동 주입(2) - 빈 이름과 한정사
  8. 의존 자동 주입(3) - @Autowired의 필수 여부, 자동 주입과 명시적 의존 주입
  9. 컴포넌트 스캔 - @Component, @ComponentScan 사용하기
  10. 빈 객체의 라이프사이클과 범위 (Life Cycle & Scope of Bean)
  11. AOP 프로그래밍(1) - 프록시와 AOP
  12. AOP 프로그래밍(2) - 스프링에서의 AOP
728x90
반응형

댓글