AOP는 Aspect Oriented Programming의 약자로, 관점 지향 프로그래밍이라고 불린다.
AOP는 애플리케이션의 기능을 핵심 기능과 부가 기능을 분리하여 관점을 기준으로 각 기능을 모듈화하는 기법이다.
여기서 핵심 기능
은 객체가 제공하는 고유 기능이고, 부가 기능
은 핵심 기능을 보조하기 위해 제공되는 기능으로 예를 들어 로깅과 같은 기능이 여기에 해당되며, 보통 여러 곳에서 공통으로 사용한다.
공통으로 사용되는 기능이 여러 모듈에 흩어져있는 것을 하나로 모듈화하여 핵심 비즈니스 로직과 분리하는 것이 AOP의 목적이다.
Aspect란, 부가 기능과 부가 기능을 어디에 적용할지 선택하는 기능을 합해서 만든 하나의 모듈이다.
Aspect
: 어드바이스 + 포인트컷을 모듈화한 것.Target
: 어드바이스를 받는 객체(Aspect를 적용하는 곳). 포인트컷으로 결정된다.Advice
: 부가 기능. 특정 조인 포인트에서 Aspect에 의해 취해지는 조치.Join Point
: Advice가 적용될 위치, 끼어들 수 있는 지점. 메서드 진입 지점, 생성자 호출 시점, 필드에서 값을 꺼내올 때 등 다양한 시점에 적용가능하다.PointCut
: 조인 포인트 중에서 어드바이스가 적용될 위치를 선별하는 기능. 'A란 메서드의 진입 시점에 호출할 것'과 같이 더욱 구체적으로 Advice가 실행될 지점을 정할 수 있다.weaving
: Aspect를 대상 객체에 연결시켜 관점지향 객체로 만드는 과정. 어드바이스를 비즈니스 로직 코드에 삽입하는 것을 의미한다.컴파일 시점
: 실제 대상 코드에 애스팩트를 통한 부가 기능 호출 코드가 포함된다. AspectJ를 직접 사용해야 한다.클래스 로딩 시점
: 실제 대상 코드에 애스팩트를 통한 부가 기능 호출 코드가 포함된다. AspectJ를 직접 사용해야 한다.런타임 시점
: 실제 대상 코드는 그대로 유지된다. 대신에 프록시
를 통해 부가 기능이 적용된다. 따라서 항상 프록시를 통해야 부가 기능을 사용할 수 있다. 스프링 AOP는 이 방식을 사용한다.프록시 방식의 AOP
를 적용한다.프록시
패턴 기반의 AOP 구현체, 프록시 객체를 쓰는 이유는 접근 제어 및 부가기능을 추가하기 위함이다.JDK 동적 프록시
혹은 CGLIB 프록시
이다.프록시는 타겟을 감싸서 타겟의 요청을 대신 받아주는 Wrapping 오브젝트이다. 클라이언트에서 타겟을 호출하게 되면 타겟이 아닌, 타겟을 감싸고 있는 프록시가 호출된다. 이때 프록시는 타겟 메소드 실행 전후로 부가 기능을 실행하도록 구성되어 있다.
다만, 프록시 패턴은 타겟 하나 하나마다 프록시 객체를 정의해야하므로 번거롭고 코드의 중복이 생긴다는 점이 있다. 그래서 Spring AOP에서는 런타임 시에 JDK Dynamic Proxy 또는 CGLIB를 활용하여 프록시를 생성해준다.
인터페이스
를 구현한 프록시 객체를 생성한다.상속
받아서 프록시 객체를 생성한다.@Around
: 메서드 호출 전후에 수행, 가장 강력한 어드바이스, 조인 포인트 실행 여부 선택, 반환 값 변환, 예외 변환 등이 가능@Before
: 조인 포인트 실행 이전에 실행@AfterReturning
: 조인 포인트가 정상 완료 후 실행 @AfterThrowing
: 메서드가 예외를 던지는 경우 실행@After
: 조인 포인트가 정상 또는 예외에 관계없이 실행(finally)🔖 순서
스프링은 5.2.7 버전부터 동일한 @Aspect 안에서 동일한 조인포인트의 우선순위를 정했다.
실행 순서:@Around
→@Before
→@After
→@AfterReturning
→@AfterThrowing
어드바이스가 적용되는 순서는 이렇게 적용되지만, 호출 순서와 리턴 순서는 반대라는 점을 알아두자.
포인트컷 표현식은 execution 같은 포인트컷 지시자(Pointcut Designator)로 시작한다. 줄여서 PCD라 한다.
execution
: 메소드 실행 조인 포인트를 매칭한다. 스프링 AOP에서 가장 많이 사용하고, 기능도 복잡하다.within
: 특정 타입 내의 조인 포인트를 매칭한다. 즉, 해당 타입이 매칭되면 그 안의 메서드들이 자동으로 매칭된다. execution
에서 타입 부분만 사용한다고 보면 된다.args
: 인자가 주어진 타입의 인스턴스인 조인 포인트. execution 의 args 부분과 비슷하지만, 부모 타입을 허용하며 실제 넘어온 파라미터 객체 인스턴스를 보고 판단한다.this
: 스프링 빈 객체(스프링 AOP 프록시)를 대상으로 하는 조인 포인트.target
: Target 객체(스프링 AOP 프록시가 가르키는 실제 대상)를 대상으로 하는 조인 포인트.@target
: 실행 객체의 클래스에 주어진 타입의 애노테이션이 있는 조인 포인트. 부모 클래스의 메서드까지 어드바이스를 적용한다.@within
: 주어진 애노테이션이 있는 타입 내 조인 포인트. 부모 클래스의 메서드에는 어드바이스를 적용하지 않는다.@annotation
: 메서드가 주어진 애노테이션을 가지고 있는 조인 포인트를 매칭한다.@args
: 전달된 실제 인수의 런타임 타입이 주어진 타입의 애노테이션을 갖는 조인 포인트.bean
: 스프링 전용 포인트컷 지시자. 스프링 빈의 이름으로 포인트컷을 지정한다.🔖 매개변수 전달
this, target, args,@target, @within, @annotation, @args 는 어드바이스에 매개변수를 전달할 수 있다.