내가 이해한 AOP 심화 기능
AOP는 단순하게 귀찮음을 덜하게 만들기 위해서 만들어졌다고 볼수있다.
모든 메서드의 성능 테스트를 부탁하는 요청이나, 트랜젝션, 보안이나 이러한 공통적인 기능들을 한번의 코드 작성으로 모든 메서드 또는 내가 지정한 많은 메서드에 적용시켜 중복되는 코드를 줄일수 있는 방법이다.
애플리케이션에는 핵심기능과 부가기능 이렇게 두가지가 하나의 객체로 들어가게 되는데 서비스를 실행하면 핵심 기능과 부가 기능이 함께 실행된다. 핵심기능은 중복이 되지않지만, 부가기능같은 경우는 여러곳에 공통적으로 적용되기 때문에 번거롭고 중복 코드가 생기게 된다. 따라서 핵심 기능 객체에 공통적으로 적용되는 부가기능을 AOP를 사용하여 적어주는것이다.
OOP는 중복되는 코드를 메소드로 만들어서 메소드가 필요한곳에 다 적어주는 것이다.
하지만 이 중복 코드를 1000메소드에 적어주어야 한다면, 모든 기능들에 다 적어야하는 공통 메소드라면 어떻게 해야 할까? 일일이 다 적는다는건 유지보수측면 뿐만 아니라 너무나도 귀찮다.
AOP는 이러한 기능을 하기 위해서 등장했다고 보면된다.
AOP는 OOP를 대신하는 개념이아니라, OOP를 더욱 OOP스럽게 사용할 수 있도록 도와주는 개념이다.
OOP의 한계를 극복하기 위한 패러다임이다.
AOP는 중복되는 코드를 한번만 적고 그것을 어디에 적용시킬지, 모든 기능에 다 적용시킬지 정해서 OOP처럼 메소드를 각각 다 적어줄 필요가 없다. 훨씬 수월하다. 또한 유지보수에도 더욱 용이하다. (공통으로 들어가는 로직 하나만 수정하면 되니까!)
ex) 로깅, 성능테스트, 보안, 트랜젝션 등등 공통적으로 들어가는 기능
Adivce는 기본적으로 순서를 보장하지 않는다.
순서를 지정하고 싶으면 @Aspect
적용 단위로
org.springframework.core.annotation.@Order
애너테이션을 적용해야함
Adivce의 종류는
Around는 가장 강력한 어드바이스이며 대부분의 기능을 제공하지만, 타겟 등 고려해야할 상항이 있을 때 정상적으로 작동이 되지 않는 경우가 있다.
포인트컷은 관심 조인 포인트를 결정하므로 어드바이스가 실행되는 시기를 제어할 수 있다.
AspectJ는 포인트컷을 편리하게 표현하기 위해 특별한 표현식을 제공한다.
@Pointcut("execution(* transfer(..))") // 포인트컷 표현식
private void anyOldTransfer() {} // 포인트컷 서명
포인트컷 표현식은 AspectJ Pointcut expression => AspectJ가 제공하는 포인트컷 표현식을 줄여서 표현하는 것이다.
포인트컷 표현식은 execution같은 포인트컷 지시자(Pointcut Designator, PCD)로 시작한다.
종류 | 설명 |
---|---|
execution | 메서드 실행 조인트 포인트를 매칭한다. 스프링 AOP에서 가장 많이 사용하며, 기능도 복잡하다. |
within | 특정 타입 내의 조인 포인트를 매칭한다. |
args | 인자가 주어진 타입의 인스턴스인 조인 포인트 |
this | 스프링 빈 객체(스프링 AOP 프록시)를 대상으로 하는 조인 포인트 |
target | Target 객체(스프링 AOP 프록시가 가르키는 실제 대상)를 대상으로 하는 조인 포인트 |
@target | 실행 객체의 클래스에 주어진 타입의 애너테이션이 있는 조인 포인트 |
@within | 주어진 애너테이션이 있는 타입 내 조인 포인트 |
@annotation | 메서드가 주어니 애너테이션을 가지고 있는 조인 포인트를 매칭 |
args | 전달된 실제 인수의 런타임 타입이 주어진 타입의 애너테이션을 갖는 조인 포인트 |
been | 스프링 전용 포인트컷 지시자이고 빈의 이름으로 포인트컷을 지정한다. |
execution
을 가장 많이 사용하고 나머지는 자주 사용하지 않습니다.
포인트컷 표현식은
&&, ||, !
를 사용하여 결합이 가능하다.
이름으로 Pointcut 표현식을 참조할 수 있다.
@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
은 메서드 실행이 거래 모듈의 공개 메서드를 나타내는 경우 일치하다.JoinPoint는 AOP 적용 위치를 나타낸다.
JoinPoint.getArgs() : JoinPoint에 전달된 인자를 배열로 반환한다.
JoinPoint.getThis() : AOP 프록시 객체를 반환한다.
JoinPoint.getTarget() : AOP가 적용된 대상 객체를 반환한다.
JoinPoint.getSignature() : 조언되는 메서드에 대한 설명을 반환한다.
Signature
: 객체가 선언하는 모든 연산은 연산의 이름, 매개변수로 받아들이는 객체들을 시그니처라고 한다.JoinPoint.toString() : 조언되는 방법에 대한 유용한 설명을 인쇄한다.