프록시
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형이여야 함