백엔드/프레임워크

[토비의 스프링] 6장: AOP

박지환 2023. 2. 18. 16:29
토비의 스프링: Vol. 1: 스프링의 이해와 원리

스프링의 3대 기반기술

  • IoC/DI
  • 서비스 추상화
  • AOP

단위 테스트

고립된 단위 테스트: 고립된 테스트를 하면 테스트가 다른 의존 대상에 영향을 받을 경우를 대비해 복잡하게 준비할 필요가 없을 뿐만 아니라, 테스트 수행 성능도 크게 향상된다

단위 테스트와 통합 테스트

  • 단위 테스트: 목 오브젝트 등의 테스트 대역을 이용해 의존 오브젝트나 외부의 리소스를 사용하지 않도록 고립시켜서 수행하는 테스트
  • 통합 테스트: 두 개 이상의, 성격이나 계층이 다른 오브젝트가 연동하도록 만들어 테스트하거나, 외부의 DB나 파일, 서비스 등의 리소스가 참여하는 테스트

테스트 작성 툴

목 프레임워크: Mockito와 같은 목 오브젝트 지원 프레임워크 등을 이용하여 목 오브젝트를 편리하게 작성할 수 있음

프록시 패턴

프록시(proxy): 자신이 클라이언트가 사용하려고 하는 실제 대상인 것처럼 위장해서 클라이언트의 요청을 받아주는 대리자, 대리인의 역할을 하는 대리 오브젝트

타깃(target), 실체(real object): 프록시를 통해 최종적으로 요청을 위임받아 처리하는 실제 오브젝트

프록시의 사용목적

  1. 클라이언트가 타깃에 접근하는 방법 제어
  2. 타깃에 부가적인 기능을 부여

데코레이터, 프록시 디자인 패턴

  • 데코레이터 패턴: 타깃에 부가적인 기능을 런타임 시 다이내믹하게 부여해주기 위해 프록시를 사용하는 패턴
  • 프록시 패턴: 프록시를 사용하는 방법 중에서 타깃에 대한 접근 방법을 제어하려는 목적을 가지고 사용하는 패턴
  • 리플렉션: 자바의 코드 자체를 추상화해서 접근하도록 만든 자바 API (java.lang.reflection)

다이내믹 프록시

다이내믹 프록시: 프록시 팩토리에 의해 런타임 시 다이내믹하게 만들어지는 프록시 오브젝트, 자바의 리플렉션 API를 이용하여 프록시를 손쉽게 작성할 수 있음 (목 오브젝트 지원 프레임워크 등을 이용하여 목 오브젝트를 편리하게 작성하는 것 처럼)

다이내믹 프록시의 동작방식
  • 팩토리 빈: 스프링을 대신해서 오브젝트의 생성로직을 담당하도록 만들어진 특별한 빈

프록시 팩토리 빈 방식의 장점과 한계

장점

  • 부가기능을 가진 프록시를 생성하는 팩토리 빈을 만들어두면 타깃의 타입에 상관없이 재사용 가능 (프록시 팩토리 빈의 재사용)
  • 데코레이터 패턴이 적용된 프록시를 쉽게 활용할 수 있음

한계

  • 클래스 단위로 부가기능을 한 번에 제공할 수 없음
  • 하나의 타깃에 여러 개의 부가기능을 적용하는 것이 힘듬
  • 핸들러가 프록시 팩토리 빈 개수만큼 만들어져서 중복됨
  • 스프링의 프록시 팩토리 빈 (ProxyFactoryBean)

스프링에서의 프록시 팩토리

작은 단위의 템플릿/콜백 구조를 응용해서 적용했기 떄문에 템플릿 역할을 하는 MethodInvocation을 싱글톤으로 두고 공유할 수 있음 → 스프링이 제공해주는 프록시 추상화 기능

어드바이스(advice): 타깃 오브젝트에 적용하는 부가기능을 담은 오브젝트를 스프링에서 부르는 말 → ProxyFactoryBeanaddAdvice로 여러 개의 부가기능을 제공하는 프록시를 만들 수 있음

ProxyFactoryBean은 두 가지 확장 기능인 부가기능(advice)와 메소드 선정 알고리즘(pointcut)을 활용하는 유연한 구조를 제공함

빈 후처리기를 이용한 자동 프록시 생성기로 여러 개의 빈에 프록시를 적용할 수 있다

자동 프록시 생성용 빈 후처리기인 DefaultAdvisorAutoProxyCreator는 자동으로 빈 오브젝트를 프록시 빈으로 바꿔줌

포인트컷 표현식으로 복접하고 세밀한 기준을 통해 클래스나 메소드를 선정 할 수 있음

부가기능의 모듈화: 핵심기능에 부여되는 부가기능을 효과적으로 모듈화하는 방법: DI, 데코레이터 패턴, 다이내믹 프록시, 오브젝트 생성 후처리, 자동 프록시 생성, 포인트컷

스프링 용어

  • 어드바이스: 부가기능을 제공하는 오브젝트
  • 포인트컷: 메소드 선정 알고리즘을 담은 메소드
  • 어드바이저 = 포인트컷(메소드 선정 알고리즘) + 어드바이스(부가기능)

AOP

AOP: 애스펙트 지향 프로그래밍

애스펙트(aspect): 핵심기능에 부가되어 의미를 갖는 특별한 모듈, 부가기능 모듈, 어드바이스와 포인트컷을 가지고 있음

AOP(Aspect Oriented Porgramming) 애스펙트 지향 프로그래밍: 애플리케이션의 핵심적인 기능에서 부가적인 기능을 분리해서 애스펙트라는 독특한 모듈로 만들어서 설계하고 개발하는 방법

AOP는 OOP를 돕는 보조적인 기술

애플리케이션을 특정한 관점을 기준으로 바라볼 수 있게 해준다는 의미에서 AOP를 관점 지향 프로그래밍이라고도 함

스프링은 프록시 방식의 AOP임

AspectJ는 프록시를 사용하지 않고, 바이트코드 생성시 이를 조작하여 부가기능을 넣어주는 방식의 AOP임

AOP의 용어

  • 타킷: 부가기능을 부여할 대상
  • 어드바이스: 타깃에게 제공할 부가기능을 담은 모듈
  • 조인 포인트: 어드바이스가 적용될 수 있는 위치 (스프링의 프록시 AOP에서 조인 포인트는 메소드의 실행 단계뿐)
  • 포인트컷: 어드바이스를 적용할 적용 포인트를 선별하는 작업 또는 그 기능을 정의한 모듈
  • 프록시: 클라이언트와 타깃 사이에 투명하게 존재하면서 부가기능을 제공하는 오브젝트 (스프링은 프록시를 이용해 AOP를 지원함)
  • 어드바이저: 포인트컷과 어드바이스를 하나씩 갖고 있는 오브젝트 (어떤 부가기능(어드바이스)을 어디에(포인트컷) 전달할 것인가를 알고 있는 AOP의 가낭 기본이 되는 모듈)
  • 애스펙트: AOP의 기본 모듈, 한 개 또는 그 이상의 포인트컷과 어드바이스의 조합으로 만들어짐, 보통 싱글톤으로 존재함
  • AOP 네임스페이스: 스프링은 aop 스키마를 제공해줘서 AOP 관련 빈들을 간편하게 등록 할 수 있음. 자동 프록시 생성기, 어드바이스, 포인트컷, 어드바이저를 빈으로 쉽게 등록 가능함

트랜잭션 속성 관리

트랜잭션 전파(transaction propagation): 트랜잭션의 경계에서 이미 진행 중인 트랜잭션이 있을 때 또는 없을 때 어떻게 동작할 것인가를 결정하는 방식

  • PROPAGATION_REQUIRED: 진행 중인 트랜잭션이 없으며 새로 시작하고, 이미 시작된 트랜잭션이 있으면 이에 참여 (DefaultTransactionDefinition의 트랜잭션 전파 속성이 이에 속함)
  • PROPAGATION_REQUIRES_NEW: 항상 새로운 트랜잭션을 시작함
  • PROPAGATION_NOT_SUPPORTED: 트랜잭션 없이 동작
  • getTransaction() 메소드: 트랜잭션 전파 속성과 현재 진행 중인 트랜잭션에 따라 새로운 트랜잭션을 시작할 수도 있고, 이미 진행 중인 트랜잭션에 참여할 수도 있음

 

격리수준: 모든 DB 트랜잭션은 격리수준(isolation level)를 갖고 있어야 함, 적절하게 격리수준을 조정해서 가능한 한 많은 트랜잭션을 동시에 진행시키면서도 문제가 없도록 해야 함 (DefaultTransactionDefinition의 격리수준은 ISOLATION_DEFAULT: DataSource에 설정되어 있는 디폴트 격리수준을 따름)

  • 제한시간: 트랜잭션을 수행하는 제한시간(timeout)을 설정할 수 있다. (DefaultTransactionDefinition의 기본 설정: 제한 시간 없음)
  • 읽기전용: 읽기전용(read only)로 설정해두면 트랜잭션 내에서 데이터를 조작하는 시도를 막아줄 수 있고, 성향 향상 가능
  • TransactionDefinition 타입 오브젝트를 사용하면 네 가지 속성을 이용해 트랜잭션의 동작방식을 제어할 수 있음
  • 트랜잭션 인터셉터(TransactionInterceptor)를 통해 어드바이스의 수정 없이 트랜잭션 속성을 적용 가능

트랙잭션 전파 방식, 격리수준, 읽기 전용, 제한 시간, 체크 예외 중 롤백 대상을 지정하여 트랜잭션 속성을 적용 가능

포인트컷과 트랜잭션 속성의 적용 전략

  • 트랜잭션 포인트컷 표현식은 타입 패턴이나 빈 이름을 이용한다
  • 공통된 메소드 이름 규칙을 통해 최소한의 트랜잭션 어드바이스와 속성을 정의한다
  • 프록시 방식 AOP는 같은 타깃 오브젝트 내의 메소드를 호출할 때는 적용되지 않는다

 

트랜잭션 속성 적용

트랜잭션 경계설정의 일원화: 특정 계층의 경계를 트랜잭션 경계와 일치시키는 것이 바람직함. 보통 비즈니스 로직을 담고 있는 서비스 계층 오브젝트의 메소드가 트랜잭션 경계를 부여하기에 가장 적절함

서비스 계층을 경계로 정했다면 이에 따라 다른 계층이나 모듈에서 DAO에 직접 접근 하는 것은 차단해야 하고, 오로지 서비스 계층을 거쳐 DAO에 접근하게 만들어야 함

애노테이션 트랜잭션: 스프링은 직접 타깃에 트랜잭션 속성정보를 가진 애노테이션을 지정하는 방법을 제공함

@Transactional 애노테이션: 메소드마다 @Transactional을 부여하고 속성을 지정할 수 있지만, 코드가 중복되고 지저분해 짐

스프링의 대체 정책 (메소드의 속성을 확인할 때 타깃 메소드 → 타깃 클래스 → 선언 메소드 → 선언 타입(클래스, 인터페이스) 순서에 따라 @Transactional이 적용됐는지 차례로 확인하고, 가장 먼저 발견되는 속성정보를 사용함)을 이용하게 해줌

트랜잭션 전파 속성을 매우 유용함 (PROPAGATION_REQUIRED 등으로 전파 속성을 지정해줄 경우, 다양한 크기의 트랜잭션 작업을 만들 수 있음 → 코드 중복을 피하고, 애플리케이션을 작은 기능 단위로 쪼개서 개발할 수 있음)

  • 선언적 트랜잭션(declarative transaction): AOP를 이용해 코드 외부에서 트랜잭션의 기능을 부여해주고 속성을 지정할 수 있게 하는 방법
  • 프로그램에 의한 트랜잭션(programmatic transaction): 개별 데이터 기술의 트랜잭션 API를 사용해 직접 코드 안에서 사용하는 방법
  • 스프링은 둘 다 지원함

트랙잭션의 자유로운 전파와 그로 인한 유연한 개발을 가능하게 한 기술

  • AOP: 프록시를 이용한 트랜잭션 부가기능을 간단하게 애플리케이션 전반에 적용 가능
  • 트랜잭션 추상화: 데이터 액세스 기술에 상관없이, 트랜잭션 기술에 상관 없이 DAO에서 일어나는 작업들을 하나의 트랜잭션으로 묶어서 추상 레벨에서 관리하게 해줌
  • 트랜잭션 추상화가 제공하는 트랜잭션 동기화 기술과 트랜잭션 전파 속성 덕분에 트랜잭션을 원하는 대로 묶을 수 있음 → 이러한 속성은 테스트 등에서 유용함: 롤백 테스트 (테스트 내의 모든 DB 작업을 하나의 트랜잭션 안에서 동작하게 하고 테스트가 끝나면 무조건 롤백해버리는 테스트)

테스트를 위한 트랜잭션 애노테이션

  • @Transactional: 테스트 메소드에 트랜잭션 경계가 자동으로 설정됨. 이를 이용하면 테스트 내에서 진행하는 모든 트랜잭션 관련 작업을 하나로 묶어줄 수 있음. 테스트용 트랜잭션은 테스트가 끝나면 자동으로 롤백함
  • @Rollback: 트랜잭션은 적용되지만 롤백을 원치 않는다면 @Rollback(false) 지정
  • @TransactionConfiguration: 롤백에 대한 공통 속성을 클래스 레벨에서 지정 가능
  • @Transactional(propagation=Propagation.NEVER): 트랜잭션을 시작하지 않음
  • 해당 애노테이션을 잘 활용하면 효과적인 DB 테스트를 할 수 있음

정리

부가기능을 모듈화할 수 있는 기술: AOP

주요 내용

  • 트랜잭션 경계설정 코드를 분리해서 별도의 클래스로 만들고 비즈니스 로직 클래스와 동일한 인터페이스를 구현하면 DI의 확장 기능을 이용해 클라이언트의 변경 없이도 깔끔하게 분리된 트랜잭션 부가기능을 만들 수 있다
  • 트랜잭션처럼 환경과 외부 리소스에 영향을 받는 코드를 분리하면 비즈니스 로직에만 충실한 테스트를 만들 수 있다
  • 목 오브젝트를 활용하면 의존관계 속에 있는 오브젝트도 손쉽게 고립된 테스트로 만들 수 있다
  • DI를 이용한 트랜잭션의 분리는 데코레이터 패턴과 프록시 패턴으로 이해될 수 있다
  • 번거로운 프록시 작성은 JDK의 다이내믹 프록시를 사용하면 간단하게 만들 수 있다
  • 다이내믹 프록시는 스태틱 팩토리 메소드를 사용하기 때문에 빈으로 등록하기 번거롭다. 따라서 팩토리 빈으로 만들어야 한다. 스프링은 자동 프록시 생성 기술에 대한 추상화 서비스를 제공하는 프록시 팩토리 빈을 제공한다
  • 프록시 팩토리 빈의 설정이 반복되는 문제를 해결하기 위해 자동 프록시 생성기와 포인트컷을 활용할 수 있다. 자동 프록시 생성기는 부가기능이 담긴 어드바이스를 제공하는 프록시를 스프링 컨테이너 초기화 시점에 자동으로 만들어준다
  • 포인트컷은 AspectJ 포인트컷 표현식을 사용해서 작성하면 편리하다
  • AOP는 OOP만으로는 모듈화하기 힘든 부가기능을 효과적으로 모듈화하도록 도와주는 기술이다
  • 스프링은 자주 사용되는 AOP 설정과 트랜잭션 속성을 지정하는 데 사용할 수 있는 전용 태그를 제공한다
  • AOP를 이용해 트랜잭션 속성을 지정하는 방법에는 포인트컷 표현식과 메소드 이름 패턴을 이용하는 방법과 타깃에 직접 부여하는 @Transactional 애노테이션을 사용하는 방법이 있다
  • @Transactional을 이용한 트랜잭션 속성을 테스트에 적용하면 손쉽게 DB를 사용하는 코드의 테스트를 만들 수 있다

 

Reference: http://www.yes24.com/Product/Goods/7516721

 

토비의 스프링 3.1 Vol. 1 스프링의 이해와 원리 - YES24

대한민국 전자정부 표준 프레임워크 스프링을 설명하는 책!단순한 예제를 스프링 3.0과 스프링 3.1의 기술을 적용하며 발전시켜 나가는 과정을 통해 스프링의 핵심 프로그래밍 모델인 IoC/DI, PSA, A

www.yes24.com