[스프링 AOP]_01 개념 소개

3 minute read

스프링 AOP 개념 소개

Aspect-oriendted Programming (AOP)은 OOP를 보완하는 수단으로, 흩어진 Aspect를 모듈화 할 수 있는 프로그래밍 기법.

흩어진 관심사 (Crosscutting Concerns)

흩어진 관심사

AOP를 적용하면?

AOP 적용

AOP 주요 개념

● Aspect와 Target
● Advice
● Join point와 Pointcut

AOP 구현체

● https://en.wikipedia.org/wiki/Aspect-oriented_programming
● 자바
		○ AspectJ
		○ 스프링 AOP

AOP 적용 방법

● 컴파일
● 로드 타임
● 런타임

스프링 AOP

AOP 구현체를 제공하며 자바에 만들어져있는 AspectJ라는 또 다른 AOP 구현체와 연동해서 사용할 수 있는 기능도 제공한다.

스프링 자체에서 구현한 스프링 AOP기능을 활용할 수도 있게해준다.

이 기능을 기반으로 스프링 트랜젝션이나 여러가지 다른 기능들이 적용되고 있다. (캐시 기능 등)

AOP란?

  • 흩어진 Aspect를 모듈화 할 수 있는 프로그래밍 기법
  • OOP와 서로 보완 관계이다. 좀 더 OOP를 잘 할 수 있도록 도와주는 것이므로

  • Concerns : 여러 클래스 여러 메서드에 거쳐서 나타나는 비슷한 코드들

흩어진 관심사 (Crosscutting Concerns)

흩어진 관심사

AOP를 적용하면?

AOP 적용

A, B, C class 모두 트랜잭션이 필요하다고 생각해보자. 트랜잭션 시, set auto commit을 false로 만들고 쿼리를 만들어서 실행하고 맨 마지막에 commit이나 롤백을 해야한다. 즉, 기존의 서비스 코드를 감싸야 한다.

A, C 클래스에서 성능관련 로깅을 할 때, 해당 메서드 실행시간이 얼마나 걸리는지 로깅을 하는 기능을 추가한다고 하면 비슷한 코드가 A와 C 클래스에 중복이 될 것이다.

각각의 concern들의 코드에 변경이 일어난다면 해당 concern들을 사용한 모든 코드에서 수정을 해줘야 한다. ⇒ 유지보수가 어렵다.

AOP는 이 문제를 Aspect로 해결한다. 흩어져 있는 관심사를 모은다. “모듈화 한다.”

각각의 concern별로 Aspect를 만든다. 실제 A, B, C 클래스에서 하던 일을 Aspect에 독립적으로 정의하고, 정의된 일을 어디에 적용해야 되는지 해당 정보를 입력해준다.

AOP 용어

  • Aspect : 관심사(여러 메서드에서 비슷하게 나타나는 코드)를 묶은 것. 하나의 모듈

  • 모듈 : AdvicePointcut이 들어간다.
  • Advice : 해야할 일들
  • Pointcut : 어디에 적용해야되는지에 대한 정보
    • Join point 중, 구체적인 Subset인 Pointcut으로 적용시점을 정할 수 있다.
    • ex) Class A에서 B라는 메서드를 호출했을 때만 이 Advice를 적용해라
  • Target : 적용이되는 대상 (ex. Class A, Class B, Class C)

  • Join point : (합류점) Advice를 끼워 넣을 수 있는 지점
    • 가상 실질적으로 많이 쓰이는 Join point는 메소드 실행 시점이다. “메서드 실행할 때 이 Advice를 집어 넣어라.”
    • 생성자 호출 직전, 생성자를 호출 했을 때, 필드에 접근하기 전, 필드에서 값을 가져갔을 때 등등…

AOP 구현체

  • 많은 AOP 구현체가 있다.

  • https://en.wikipedia.org/wiki/Aspect-oriented_programming

    implementation으로 검색하면 각 언어별 구현체를 확인할 수 있다.

  • 자바 구현체

    • AspectJ
      • 엄청나게 다양한 기능과 Join point를 제공한다.
    • 스프링 AOP
      • 국한적으로 제공한다.

AOP 적용 방법

  • 컴파일 타입

    • java 파일을 class 파일로 만들 때, 바이트 코드들을 조작하면서 조작이 된 바이트 코드를 생성해내는 것이다.
    • 이미 컴파일시 적용해서 AOP가 적용된 바이트 코드를 만들었으므로 로드 타임/런타임 시에 성능 부하가 없다.
    • 하지만 이렇게 만드려면 별도의 컴파일을 한번 더 해야한다.
  • 로드 타임

    • A라는 클래스는 A 클래스안의 코드들만 가지고 순수하게 컴파일한다. A 클래스파일을 로딩하는 시점에 로딩하는 클래스 정보를 변경한다. Load Time Weaving(로드 타임 위빙) 로드 타임에 Aspect를 끼워 넣는 것이다.

      A클래스 바이트 코드는 순수하지만, JVM에 로딩한 메모리 상에서는 Aspect가 끼워져있다.

    • 클래스 로딩 시점에 약간의 성능 부하가 생길 수 있다.

    • 로드 타임 위버를 설정(Java Agent)해줘야 한다.

  • 런타임 (추천 방법)

    • 스프링 AOP가 사용하는 방법
    • A라는 빈에다가 Aspect가 가진 메서드를 적용해야 된다는 것을 스프링이 알고 있다.
    • Spring Application에서 A라는 빈을 만드는 시점은 런타임이다. A라는 클래스 타입의 빈을 만들 때, A라는 타입의 프록시빈을 만든다. A라는 빈을 감싼 A 타입의 프록시빈을 만든다. 이 프록시 빈이 실제 A가 가지고 있는 a 메소드를 호출하기 전에 다른일(b메서드 호출..)을 한 뒤에 a 메소드를 호출한다.
    • 초기 빈을 만들 때만 성능 비용이 추가된다. 하지만 실제 애플리케이션이 동작할 때 요청마다 성능 부하가 있는 것이 아님. (로드 타임 방식의 성능 부하와 비슷할 듯)
    • 별도의 컴파일러나 자바 에이전트로 로드타임 위버를 설정해야 되는 등의 추가 작업이 필요 없고, 문법이 쉽고, 별도의 AOP 공부를 많이할 필요도 없다.

런타임 방식이 가장 현실적이고 합리적인 자주 쓰게될 방법이라고 생각한다.

하지만 AspectJ가 제공하는 다양한 Joinpoint를 사용해야되는 경우가 있다. 그런 경우에는 AspectJ로 Aspect 컴파일러로 컴파일 하거나 Java Agent를 설정해서 로드 타임 위빙하는 등의 방식을 사용해서 AspectJ와 연동해서 사용할 수 있다.