포인트컷은 관심 조인 포인트를 결정한다. 어드바이스가 실행되는 시기를 제어할 수 있다.
AspectJ는 포인트컷을 편리하게 표현하기 위한 특별한 표현식을 제공한다.
@Pointcut("execution(* hello.aop.order..*(..))")
@Pointcut("execution(* transfer(..))") // 포인트컷 표현식
private void anyOldTransfer() {} // 포인트컷 서명
포인트컷 지시자
포인트컷 표현식은 execution
같은 포인트컷 지시자(Pointcut Designator, PCD)로 시작한다.
execution
을 가장 많이 사용한다.
포인트컷 표현식은 &&, ||, !
를 사용해 결합할 수 있다. 이름으로 포인트컷 표현식을 참조할 수도 있다.
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {} // (1)
@Pointcut("within(com.xyz.myapp.trading..*)")
private void inTrading() {} // (2)
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {} // (3)
anyPublicOperation
은 메서드 실행 조인 포인트가 공용 메서드의 실행을 나타내는 경우 일치한다.
in Trading
메서드 실행이 거래 모듈에 있는 경우에 일치한다.
tradingOperation
은 메서드 실행이 거래 모듈의 공개 메서드를 나타내는 경우 일치한다.
AOP의 적용 위치
AOP는 메서드 실행 위치 뿐만 아니라 다양한 위치에 적용할 수 있다.
적용 가능 지점을 Join Point(조인 포인트)라 하고, 조인 포인트는 생성자와 필드 값 접근, static 메서드 접근, 메서드 실행 위치에 적용할 수 있다.
AOP를 수행하는 메소드는 Join Point 인스턴스를 인자로 받게 된다. 조인 포인트 인스턴스에서 조인 포인트 지점의 정보를 얻어내야 한다.
Join Point
조인 포인트는 추상적인 개념이며 AOP를 적용할 수 있는 지점을 의미한다.
AspectJ를 사용해 컴파일 시점과 클래스 로딩 시점에 적용하는 AOP는, 바이트코드를 실제 조작하기 때문에 해당 기능을 모든 지점에 다 적용할 수 있다.
프록시 방식을 사용하는 스프링 AOP는 메서드 실행 지점에만 AOP를 적용할 수 있다. 프록시는 메서드 오버라이딩 개념으로 동작한다. 생성자나 static 메서드, 필드 값 접근에는 프록시 개념이 적용될 수 없다.
프록시를 사용하는 스프링 AOP의 조인 포인트는 메서드 실행으로 제한되며, 스프링 컨테이너가 관리할 수 있는 스프링 빈에만 AOP를 적용할 수 있다.
JoinPoint 메소드는 어드바이스의 종류에 따라 사용방법이 다소 다르지만 기본적으로 어드바이스 메소드에 매개변수로 선언만 하면 된다.
JoinPoint.getArgs()
: JoinPoint에 전달된 인자를 배열로 반환한다.
JoinPoint.getThis()
: AOP 프록시 객체를 반환한다.
JoinPoint.getTarget()
: AOP가 적용된 대상 객체를 반환한다.
클라이언트가 호출한 비즈니스 메소드를 포함하는 비즈니스 객체를 반환한다.
JoinPoint.getSignature()
: 조언되는 메서드에 대한 설명을 반환한다.
클라이언트가 호출한 메소드의 시그니처(리턴타입, 이름, 매개변수) 정보가 저장된 Signature 객체를 반환한다.
`Signature` : 객체가 선언하는 모든 연산은 연산의 이름, 매개변수로 받아들이는 객체들을 말한다.
<Signature가 제공하는 메서드>
String getName() : 클라이언트가 호출한 메소드의 이름을 반환한다.
String toLongString() : 클라리언트가 호출한 메소드의 리턴타입, 이름, 매개변수를 패키지 경로까지 포함해서 반환한다.
String toShortString() : 클라이언트가 호출한 메소드 시그니처를 축약한 문자열로 반환한다.
JoinPoint.toString()
: 조언되는 방법에 대한 유용한 설명을 인쇄한다.proceed()
: 다음 어드바이스나 타켓을 호출한다.AOP는 스프링 IoC를 보완해 매우 강력한 미들웨어 솔루션을 제공한다.
Spring AOP 지원
@AspectJ
애너테이션 스타일
스키마 기반 접근
@AspectJ는 애너테이션이 있는 일반 Java 클래스로 관점을 선언하는 스타일이다.
AOP 런타임은 여전히 순수한 스프링 AOP이며, AspectJ 컴파일러나 위버에 의존하지 않는다.
@AspectJ 지원 활성화
Spring 설정에서 @AspectJ
aspect를 사용하기 위해서는 @AspectJ
aspect에 기반한 Spring AOP 설정과, 이러한 aspect에 의해 조언되는 자동 프록시 빈에 대한 Spring 지원을 활성화해야 한다.
@AspectJ 지원은 XML 또는 Java 스타일 설정으로 활성화할 수 있다.
Java 설정으로 @AspectJ 지원 활성화 하기
@Configuration
으로 @AspectJ 지원을 활성화하려면@EnableAspectJAutoProxy
애너테이션을 추가한다.
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
@AspectJ
지원이 활성화되면 @AspectJ
관점(@Aspect 애너테이션
)이 있는 클래스로 애플리케이션 컨텍스트에 정의된 모든 빈이 Spring에서 자동으로 감지되고 Spring AOP를 구성하는 데 사용된다.
<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect">
<!-- configure properties of the aspect here -->
</bean>
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}
포인트컷은 관심 조인 포인트를 결정하므로 어드바이스가 실행되는 시기를 제어할 수 있다.
포인트컷 선언은 이름과 매개변수를 포함하는 서명과 관심 있는 메소드 실행을 정확히 결정하는 pointcut 표현식의 두 부분으로 구성된다.
@Pointcut
애너테이션을 사용하여 표시한다.어드바이스는 포인트컷 표현식과 연관된다. 포인트컷과 일치하는 메서드의 실행 전후에 실행된다.