본문 바로가기

Spring

AOP 와 PSA

AOP


Aspect Oriented Programming의 약자로, 흩어진 코드를 한곳에서 관리할 수 있도록 도와주는 코딩 기법이다.

크게 두가지 방법이 있다.

  • 바이트 코드 조작 방법 => 컴파일된 .class를 조작한다.
  • 프록시 패턴 방법 => Spring AOP가 사용하는 방법

AOP가 적용된 애노테이션 중에 @Transactional(readOnly = true)을 보자.

보통 트랜잭션 처리는 트랜잭션 매니저가 트랜잭션 오토 커밋을 false로 만들고 작업이 끝나면 true로 변환한다(트랜잭션을 커밋한다). 그리고 이 작업을 내부적으로 try/catch로 묶어놨는데 에러가나면 catch 블럭에서 rollback시키다. 

Spring Data JPA 해당하는 메소드들에는 기본적으로 트랜잭션이 적용이 되어있다.

@Transactional(readOnly = true)는 기본설정을 오버라이딩한것뿐이다.

이렇게 트랜잭션은 하나의 클래스에만 적용되어있는 것이 아니라 사방에 적용이 되어있다.

이와 비슷하게 @Transactional도 동작한다. @Transactional를 보고 처리하는 코드가 어딘가에 있다.

 

애노테이션은 무엇일까?

주석과 같다. 이 주석을 어디에다 달지, 언제까지 유효한지에대한 속성만 가질 뿐이지 기능은 없다. 단지 이 애노테이션들을 처리하는 프로세서들이 있을 뿐이다.

 

쉬운 이해를 위해 AOP를 흉내내보자.

특정 애노테이션이 붙어있는 메소드가 실행될 때 그 메소드의 로그를 남기는 것을 해보자.

우선 애노테이션을 만든다.

// Annotation 생성
@Target(ElementType.METHOD) // 이 애노테이션을 어디에 붙일 수 있는지 타겟정보 명시
@Retention(RetentionPolicy.RUNTIME) // 이 애노테이션을 사용한 코드를 런타임까지 유지를 한다고 명시
public @interface LogExecutionTime {
}

위에 만든 애노테이션에대한 처리기를 만들어보자.

 

@Component // Bean만 Aspect가 될 수 있다.
@Aspect  // Aspect 역할을 한다고 명시
public class LogAspect {

    Logger logger = LoggerFactory.getLogger(LogAspect.class);

    // LogExecutionTime 애노테이션 주변으로 메소드에 명시한 일들을 하라.
    // @annotation말고 Bean도 있다.특정 Bean에 있는 모든 메소드에 적용하라. 
    // 또는 복잡한 표현식을 쓸 수 있다. 표현식을 쓰면 @LogExecutionTime을 안붙이고도 
    @Around("@annotation(LogExecutionTime)") 
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        // spring이 제공하는 stopWatch
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        Object result = joinPoint.proceed();
        stopWatch.stop();
        logger.info(stopWatch.prettyPrint());

        return result;
    }
}

실제 동작해보자

@RestController
public class SampleController {

    @Autowired
    String kimjye;

    @LogExecutionTime
    @GetMapping("/hello")
    public String context(){
        return "hello " + kimjye;
    }
}

 

PSA


PSA는 Portable Service Abstraction의 약자로, 잘 만든 인터페이스라고 생각하면 된다.

스프링에서 제공하는 대부분의 API는 PSA다.

 

@Transactional은 AOP의 예제도되지만 PSA의 예제도 된다.

@Transcational를 처리할 Aspect가 어딘가에 있다. 그리고 이 Aspect에서는 Transaction 처리 기술에 독립적인 PlatformTransactionManager라는 인터페이스를 구현했다.

그렇기 때문에 PlatformTransactionManager의 구현체들은 Bean으로 등록되어있다.

 

따라서 @Transactional은 PlatformTransactionManager을 구현했기 때문에 JpaTransactionManager에서 DataSourceTransactionManager로 변경이 되더라도 @Transactional을 처리하는 Aspect 코드는 변경이 되지 않는다.

이것이 추상화의 장점이다.

'Spring' 카테고리의 다른 글

부록  (0) 2020.01.14
Spring Boot  (0) 2020.01.14
Bean 과 DI  (0) 2020.01.14
IOC  (0) 2020.01.14
@Setter  (0) 2019.04.18