AOP

 

AOP( Aspect-Oriented Programming)
관점 지향 프로그래밍

 

다수의 모듈에 공통적으로 나타나는 부분이 존재하는데 이를 횡단 관심사(cross-cutting concern)라고 한다.
개발자들은 중복 코드를 싫어하기 때문에 이런 횡단 관심사는 단 한 번만 작성하고 싶다.
그때 AOP를 사용한다.
@Aspect
public class MyAspect {
    @Before("execution(public void aop002.Boy.runSomething ())")
    public void before(JoinPoint joinPoint) {
        System.out.println("얼굴 인식 확인: 문을 개방하라");
    }
}

@Aspect 어노테이션은 이 클래스를 AOP에서 사용하겠다는 뜻

@Before 어노테이션은 대상 메서드 실행 전에 이 메서드를 실행하겠다는 의미다.

 

중요한 것은 아래 세 개다.

  1. 스프링 AOP는 인터페이스 기반이다.
  2. 스프링 AOP는 프록시 기반이다.
  3. 스프링 AOP는 런타임 기반이다.

예시에서는 @Before을 사용했지만 프록시가 개입할 수 있는 시점은 5가지이다.

  • Arround
  • Before
  • After
  • AfterReturning
  • AfterThrowing

 

 

용어

Pointcut
  • Aspect 적용 위치 지정자 : public void aop002.Person.runSomething()
    • 여기서는 정규식과 AspectJ 표현식 등을 사용할 수 있다.
    • [접근제한자패턴] 리턴타입패턴 [패키지&클래스패턴] 매서드이름패턴(파라미터패턴) [throws 예외패턴]
    • [] 대괄호는 생략이 가능하다.
@Aspect
public class MyAspect {
    @Before("execution(* runSometing())")
    public void before(JoinPoint joinPoint) {
        System.out.println("얼굴 인식 확인: 문을 개방하라");
    }
}

*표시는 와일드 카드로 어떤 클래스의 runSometime 메서드이든 주입할 수 있다.

 

@Aspect
public class MyAspect {
    @Before("execution(* aop002.*")
    public void before(JoinPoint joinPoint) {
        System.out.println("얼굴 인식 확인: 문을 개방하라");
    }
}

@Aspect
public class MyAspect {
    @Before("execution(* aop002..")
    public void before(JoinPoint joinPoint) {
        System.out.println("얼굴 인식 확인: 문을 개방하라");
    }
}

*은 패키지 하위를 나타낼 때도 찍을 수 있으며 * aop002.*는 패키지의 모든 클래스에 적용함을 나타낸다.

비슷하게 ..는 * aop002..와 같이 사용하며 모든 하위 패키지의 모든 클래스에 적용한다.

 

@Aspect
public class MyAspect {
    @Before("execution(* run*")
    public void before(JoinPoint joinPoint) {
        System.out.println("얼굴 인식 확인: 문을 개방하라");
    }
}

메서드 이름에도 적용 가능하다.

run으로 시작하는 메서드에 적용하겠다는 뜻이다.

 

@Pointcut("execution(* aop002.Boy.*(..))")
private void boy() {}

@Before("boy()")
public void before(JoinPoint joinPoint) {
    System.out.println("얼굴 인식 확인: 문을 개방하라");
}

이렇게 포인트컷을 미리 만들어두고 사용할 수도 있다.

 

마지막으로 파라미터 패턴도 존재한다.

  • () - 인수 없음
  • (*) - 인수 1개 (타입 상관없음)
  • (..) - 인수 0~N개 (타입 상관없음)

따라서 위의 예시는 인수가 0개거나 N개인 메서드에 적용하겠다는 것을 나타낸다.

 

JoinPoint
  • 연결점 : JoinPoint joinPoint
    • Aspect 적용이 가능한 모든 지점. 이 중 Pointcut에만 적용하는 것이니 Pointcut은 JoinPoint의 부분집합인 셈이다.
    • 스프링 AOP에서는 스프링 프레임워크가 관리하는 빈의 모든 메서드에 해당한다.
    • Pointcut의 메서드가 호출되면 JointPoint에 그 메서드가 들어올 것이다.

 

Advice
  • 언제 무엇을 : @Before() public void before(JoinPoint joinPoint) { System.out.println("...");}
    • pointcut에 적용할 로직과 적용 시점

 

 

동작 원리

Spring이 프록시객체를 중간에 삽입해준다.

DispatcherServlet 과 ProductController 입장에서는 변화가 전혀 없다.

  • 호출되는 함수의 input, output 이 완전 동일.
  • "joinPoint.proceed()" 에 의해서 원래 호출하려고 했던 함수, 인수(argument) 가 전달됨.
  • → createProduct(requestDto);

'Spring' 카테고리의 다른 글

[Spring] 🙉Fixture Monkey🙉  (1) 2024.06.15
[Spring] DB 테스트 환경 분리  (0) 2024.06.13
[Spring] JUnit 5 단위 테스트  (0) 2024.06.11
[Spring] Naver, Google 로그인 (OAuth2)  (0) 2024.06.10
[Spring] Naver 로그인 (Oauth2 X)  (1) 2024.06.08

+ Recent posts