본문 바로가기
카테고리 없음

[스터디] AOP

by foreverever 2022. 8. 15.
반응형

프록시

1) 핵심 기능은 구현하지 않으며, 여러 객체에 공통으로 적용할 수 있는 기능을 구현
2) AOP의 핵심 기능

AOP 개념

1) 관점지향 프로그래밍
2) 여러 객체에 공통으로 적용할 수 있는 기능을 분리해서 재사용성을 높여주는 프로그래밍 기법
3) 핵심 기능에 공통 기능(인프라 로직)을 삽입

AOP 주요 용어

1) aspect

  • 공통 기능(부가 기능)을 가지는 대상
  • advice와 pointcut 으로 구성
  • pointcut(어디에서) + advice(무엇을 할 것인가)

2)advice

  • 언제 공통 관심 기능을 핵심 로직에 적용할지 정의
  • Before, After Returning, After Throwing, After, Arround
  • 예시 : 메서드를 호출하기 전(언제)에 트른잭션 시작

3) pointcut

  • advice가 적용될 타겟(대상)을 설정
  • 타겟 : 어떤 클래스(컨트롤러)의 어느 joinPoint(메서드)
  • 예시 : QuestionController의 updateQuestion()을 지정

4) weaving

  • 포인트컷(pointcut)에 의해 결정된 조인포인트(joinPoint)에 지정된 어드바이스(advice)를 삽입하는 과정

AOP 구현

@Aspect
public class CacheAspect {

    private Map<Long, Object> cache = new HashMap<>();

    @Pointcut("execution(public * chap07..*(long))")
    public void cacheTarget() {
    }

    @Around("cacheTarget()")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        Long num = (Long) joinPoint.getArgs()[0];
        if (cache.containsKey(num)) {
            System.out.printf("CacheAspect: Cache에서 구함[%d]\n", num);
            return cache.get(num);
        }

        Object result = joinPoint.proceed();
        cache.put(num, result);
        System.out.printf("CacheAspect: Cache에 추가[%d]\n", num);
        return result;
    }
}
@Configuration
@EnableAspectJAutoProxy
public class AppCtxWithCache {

    @Bean
    public CacheAspect cacheAspect() {
        return new CacheAspect();
    }

    @Bean
    public ExeTimeAspect exeTimeAspect() {
        return new ExeTimeAspect();
    }

    @Bean
    public Calculator calculator() {
        return new RecCalculator();
    }

}

proxy 생성 방식

1) execution 명시자 표현식
Advice를 적용할 메서드를 지정할 때 사용하며, 기본 형식은 다음과 같음

@Pointcut("execution(public * chap07..*(..))")
private void publicTarget() {

}

execution(수식어패턴 리턴타입패턴 클래스이름패턴?메서드이름패턴(파라미터패턴))

  • 수식어패턴 : 접근제어자. public, protected 등이 온다. 스프링 AOP에서는 public 메서드에만 적용 가능
  • 리턴타입패턴 : 리턴타입을 명시
  • 클래스이름패턴?메서드이름패턴 : 클래스이름 및 메서드이름을 명시 (클래스이름대신 패키지명이 올 수도 있음)
  • 파라미터패턴 : 매칭될 파라미터에 대해 명시함.

'*' 을 이용해서 모든 값을 표현
'..' 을 이용해서 0개 이상이라는 의미를 표현

예시>

1) execution(public void set*(..) )
- 수식어패턴 : public
- 리턴타입 : void
- 클래스이름 : 생략됨
- 메서드이름 : setter (set으로 시작하는 메서드)
- 파라미터패턴 : 파라미터가 0개 이상 '(..)'

 

2) execution( * chap07..() )
- 수식어패턴 : 생략됨
- 리턴타입 : * ← 전부
- 클래스이름 : chap07.* ← chap07패키지에 있는 모든 클래스. chap07 하위패키지까지는 아님. - (chap07 : 패키지명.)
- 메서드이름 : * ← 전부
- 파라미터패턴 : 공란 ← 없음

 

3) execution( * chap07...(..) )

- 수식어패턴 : 생략됨
- 리턴타입 : *   ← 전부
- 클래스이름 : chap07..*  ← chap07패키지 및 해당 패키지 하위의 모든 클래스 (chap07 :    패키지명.)
- 메서드이름 : *   ← 전부
- 파라미터패턴 : (..)  ← 0개 이상

 

4) execution( Long chap07.Calculator.factorial(..) )

- 수식어패턴 : 생략됨
- 리턴타입 : Long
- 클래스이름 : chap07.Calculator
- 메서드이름 : factorial
- 파라미터패턴 : (..)  ← 0개 이상

 

5) execution( * get() )

- 수식어패턴 : 생략됨
- 리턴타입 : *   ← 전부
- 클래스이름 : 생략됨
- 메서드이름 : getter (get으로 시작하는 메서드)
- 파라미터패턴 : *  ← 1개

 

6) execution( * get(, *) )

- 수식어패턴 : 생략됨
- 리턴타입 : *   ← 전부
- 클래스이름 : 생략됨
- 메서드이름 : getter (get으로 시작하는 메서드)
- 파라미터패턴 : *, * ← 2개

 

7) execution( * read*(Integer, ..) )
- 수식어패턴 : 생략됨
- 리턴타입 : * ← 전부
- 클래스이름 : 생략됨
- 메서드이름 : read로 시작하는 모든 메서드
- 파라미터패턴 : Integer, .. ← 1개 이상의 파라미터를 가짐. 첫번째 파라미터형은 Integer형이여야 함

반응형