이야기박스

Chapter 6. AOP(3) 포인트 컷과 트랜잭션 본문

Programming Language/Spring

Chapter 6. AOP(3) 포인트 컷과 트랜잭션

박스님 2019. 2. 8. 14:47
반응형

포인트컷이란?

특정 조건에서 어드바이스(공통 기능의 코드)를 실행하기 위한 알고리즘입니다.

즉, 횡단 공통기능을 수행하기 위한 필터라고 생각하면 쉬울 것 같습니다.


1. 스프링 트랜잭션 어노테이션

포인트 컷 표현식 + 트랜잭션 속성을 이용하여 트랜잭션을 일괄적으로 적용하는건 일반적인 상황에서는 쓰일 수 있지만, 깊게 커스터마이징이 필요한 상황에서는 적합하지 않을 수 있습니다.


@Transactional

이 어노테이션은 메소드와 타입 뿐만 아니라 클래스에도 적용 가능합니다.
- 타깃 : 메소드, 클래스, 인터페이스
// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

이런식으로 ... 


이때 TransactionAttributeSourcePointcut이라는 포인트컷과 같이 사용되는데, 이때 포인트컷은 @Transactional 어노테이션이 있다면 타깃이 무엇이든간에 포인트컷의 결과로 선정됩니다. 즉, 이 어노테이션을 쓰면 포인트컷에 자동 등록된다고 생각하면 됩니다.


이 어노테이션을 사용하기 위해서는 어플리케이션 컨텍스트에 다음 정보를 추가하면 됩니다.

<tx:annotation-driven />

트랜잭션 속성과 포인트 컷

02.png

(@Transcational 어노테이션 사용했을 경우의 Advisor 동작 방식)


TransactionInterceptor는 메소드 이름 패턴으로 부여되는 속성 정보 대신, @Transcational 어노테이션의 트랜잭션 속성을 가져옵니다. ( AnnotationTransactionAttributeSource )

그리고 동시에 포인트 컷도 @Transactional 어노테이션을 참조하게 됩니다.(?) -- 포인트 컷의 선정 대상이기도 하기 때문


이 방식을 통하여서 포인트컷과 트랜잭션 속성을 하나의 어노테이션으로 정할 수 있게 됩니다. 특히 메소드 단위까지 지정이 가능하기 때문에 커스터마이징에 아주 특화되어 있습니다.

단, 너무 남발하게 되면 코드가 지저분해지고 가독성이 저하될 수 있기 때문에 신중히 사용해야 합니다.


대체 정책

'소제목이 @Transcational 대신 어떻게 쓰는가?' 같지만 실제로는 @Transactional 어노테이션의 동작 순서를 나타낸 것입니다.

1. 타겟 메소드에 적용되어 있는가?

2. 타겟 클래스에 적용되어 있는가?

3. 선언 메소드에 적용되어 있는가?

4. 선언 타입에 적용되어 있는가?


위 과정을 거쳐서 트랜잭션 적용 대상을 판단합니다. 이 순서를 개발할 때 참조하시면 되겠습니다.


실제 사용

  <tx:attributes>
        <tx:method name="get*" read-only="true"/>
        <tx:method name="*"/>
    </tx:attributes>

이런식으로 우선순위를 정하여 사용할 수 있습니다.

위 예제 같은 경우는 get*으로 시작하는 메소드는 읽기 전용 트랜잭션 속성을 지정해주어야 합니다.


2. 트랜잭션 지원 & 테스트

트랜잭션 전파 속성을 기억하십니까? (REQUIRED, REQUIRES_NEW, NOT_SUPPORTED) 
REQUIRED로 지정해두는 경우, 앞에 트랜잭션이 진행중인 것이 없으면 새로 트랜잭션을 시작하여 줍니다. 즉, 트랜잭션 적용 때문에 불필요한 코드 중복하는 것을 피하고, 애플리케이션을 작은 기능 단위로 쪼개서 개발할 수 있습니다.


03.png


트랜잭션 지정 방법

- 선언적 트랜잭션 (Declarative transaction) : AOP를 이용해 코드 외부에서 트랜잭션의 기능을 부여해주고 속성을 지정

- 프로그램에 의한 트랜잭션 (Programmatic transcation) : 트랜잭션 API를 이용하여 직접 코드 안에 넣는 방법


트랜잭션의 자유로운 전파와 그로 인한 유연한 개발이 가능할 수 있었던 기술적 배경으로 AOP가 크게 작용하였습니다.

AOP로 인하여 프록시를 이용한 트랜잭션 부가기능을 애플리케이션 전반에 구현이 가능해졌습니다. 여기에 트랜잭션 추상화의 등장으로 선언적 트랜잭션 & 트랜잭션 전파가 손쉽게 이루어지게 되었습니다.


트랜잭션 매니저 & 동기화

PlatformTranscationManager 인터페이스를 구현한 매니저를 통해 트랜잭션 제어가 가능합니다. 또한 트랜잭션 동기화 기술이 있어 해당 정보를 저장소에 보관해 두었다가 DAO에서 공유가 가능했습니다.

해당 기술을 바탕으로 위에서 이야기했던 트랜잭션 전파도 이루어집니다. 동기화를 통해 트랜잭션 상태를 확인하며, 새롭게 참여하기도 합니다.

* 트랜잭션을 통합하는 방법

1. 메소드를 생성하여 그 안에 원하는 동작을 지정

2. 원하는 동작의 메소드들을 호출하기 전에 트랜잭션을 지정하는 방법


테스트와 @Rollback

테스트 클래스 / 메소드에 사용되는 @Transcational 어노테이션은 일반적으로 사용될 때와 기본적으로는 동일하지만, 동작이 완료되는 시점에 자동으로 롤백을 하게 됩니다. 즉 테스트에 적용되는 @Transactional은 테스트가 끝나면 기본적으로 강제 롤백시킵니다.

만약, 메소드의 롤백을 원하지 않는 경우, @Rollback 어노테이션을 사용해주면 됩니다.
@Test
@Transactional  // 테스트 클래스나 테스트 메소드에서 사용하면 기본적으로 롤백시킨다.
@Rollback(false)  // false로 지정하면 롤백시키지 않는다.
public void transactionTest() {
  ...
}

만약, 클래스의 롤백을 원하지 않는 경우, @TransactionConfiguration 어노테이션으로 롤백 여부를 지정해줄 수 있습니다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/applicationContext.xml")
@Transactional
@TransactionConfiguration(defaultRollback=false)  // 사용하는 디폴트 트랜잭션 매니저 아이디는 "transactionManager" 이다.
public class UserServiceTest {
  ...

  @Test
  @Rollback // 여기서 @Rollback 을 사용하여 이 테스트 메소드만 롤백시킬 수 있다.
  public void notRollbackTest() {
    ...
  }

  @Test
  @Transactional(propagation=Propagation.NEVER) // 이 테스트에 한해서 트랜잭션을 시작되지 않도록 할 수 있다.
  public void notUseTransactionTest() {
    ...
  }


기타

@NotTransactional : 트랜잭션 설정을 무시하고 동작하게 됩니다.
@Propagation.NEVER : 트랜잭션 전파가 안이루어집니다. 즉, 트랜잭션이 이루어지지 않습니다.



3. AOP 전체 요약

- 트랜잭션 설정과 롤백 그리고 DI
- 프록시 패턴과 어드바이저 (어드바이스 + 포인트 컷)

- 트랜잭션 전파와 어노테이션 사용

반응형

'Programming Language > Spring' 카테고리의 다른 글

Chapter 8. 스프링이란 무엇인가?  (0) 2019.03.22
Chapter 7. 스프링 핵심 기술의 응용  (0) 2019.03.21
Chapter 6. AOP(2)  (0) 2019.02.08
Chapter 6. AOP(1)  (0) 2019.01.23
Chapter 5. 서비스 추상화  (0) 2019.01.15