티스토리 뷰
프록시 생성방식
스프링은 프록시를 생성할 때, 실제 생성할 빈 객체가 인터페이스를 상속하면 프록시 타입 또한 해당 인터페이스를 상속해서 만들어지게 됩니다. 즉 다음과 같은 코드는 오류가 발생합니다.
//in Configuration code..
@Bean
public Calculator calculator() {
return new REcCalculator();
}
package main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import chap07.Calculator;
import chap07.REcCalculator;
import config.AppCtx;
public class MainAspect {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx= new AnnotationConfigApplicationContext(AppCtx.class);
//Calculator cal = ctx.getBean("calculator",Calculator.class);
REcCalculator cal= ctx.getBean("calculator",REcCalculator.class);
cal.factorial(5);
System.out.println(cal.getClass().getName());
}
}
실제 빈 객체의 타입 RECcalculator은 Calculator 인터페이스를 상속했으므로 프록시 객체를 생성할 때 Calculator을 상속해서 만들어지게 됩니다. 그러므로 RECcalculator 타입으로 캐스팅이 불가능합니다.
만약 인터페이스가 아닌 클래스를 상속해 프록시 객체를 만들고 싶다면 proxyTargetClass의 속성을 true로 바꿔주면 됩니다.
package config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import apsect.ExeTimeAspect;
import chap07.Calculator;
import chap07.REcCalculator;
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppCtx {
@Bean
public ExeTimeAspect exeTimeAspect() {
return new ExeTimeAspect();
}
@Bean
public Calculator calculator() {
return new REcCalculator();
}
}
Execution 명시자
execution 명시자의 기본형태는 다음과 같습니다.
execution([수식어패턴] 리턴패턴 [클래스패턴]메서드패턴(파라미터패턴))
대괄호안에 있는 패턴들은 생략이 가능합니다. 유의할점은 클래스패턴을 명시할 때, 패키지명까지 모두 적어야 한다는 것입니다. 아래는 execution 명시자의 예시입니다. * 패턴은 모든 값에 해당하며 .. 패턴은 0개 이상을 의미합니다.
execution(public void set*(..)) | 리턴타입이 void이고, 메서드명이 set으로 시작하며 메서드의 인자가 0개 이상인 메서드들을 지정합니다 |
execution(* chap07.*.*()) | 클래스패턴을 명시하여 패키지명까지 다 적은 것입니다. chap07 패키지내에 모든 클래스의 메서드들을 지정합니다. |
execution(* chap07..*.*()) | chap07 패키지 및 하위 패키지를 포함한 모든 메서드를 지정합니다. |
execution(Long chap07.Calculator.factorial(..)) | 리턴 타입이 Long이고 Calculator 클래스의 factorial 메서드를 지정합니다. |
execution(* get*(*)) | 메서드명이 get으로 시작하고 인자를 하나만 갖는 모든 메서드를 지정합니다. |
execution(* get*(*,*)) | 메서드명이 get으로 시작하고 인자를 두개만 갖는 모든 메서드를 지정합니다. |
execution(* read*(Integer,..)) | 메서드명이 read로 시작하고 첫번째 인자가 Integer인 하나 이상의 인자를 갖는 메서드를 지정합니다. |
Advice 적용 순서
하나의 Pointcut에 여러 Advice를 적용할 수 있습니다. 아래와 같은 새로운 Aspect를 만들어봅시다.
package apsect;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class CacheAspect {
private Map<Long,Object> cache = new HashMap<>();
@Pointcut("execution(* chap07..*.*(..))")
public void cacheTarget() {
}
@Around("cacheTarget()")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
Long num=(Long)joinPoint.getArgs()[0];
if(cache.containsKey(num)) {
System.out.println("이미 존재합니다");
return cache.get(num);
}
Object ret = joinPoint.proceed();
cache.put(num, ret);
System.out.println("cache에 추가");
return ret;
}
}
설정 클래스에 추가한 Aspect의 Bean을 만든 후 Main에서 다음과 같이 실행해보도록 합시다.
package main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import chap07.Calculator;
import chap07.REcCalculator;
import config.AppCtx;
public class MainAspect {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx= new AnnotationConfigApplicationContext(AppCtx.class);
Calculator cal= ctx.getBean("calculator",Calculator.class);
cal.factorial(5);
cal.factorial(5);
cal.factorial(7);
cal.factorial(7);
System.out.println(cal.getClass().getName());
}
}
위와 같은 실행결과가 나타난 이유는 cacheApsect의 프록시 객체는 대상 객체로써 ExeTimeAspect 프록시 객체를 사용하고 ExeTimeAspect 프록시 객체는 대상 객체로써 실제 대상 객체를 사용하기 때문입니다.
만일 Aspect의 적용순서가 중요하다면 @Order 어노테이션을 통해 Aspect의 우선순위를 지정할 수 있습니다. 위 사진에서는 cacheAspect에 @Order(1) 을 지정하고 ExeTimeAspect에 @Order(2)를 지정한 것과 동일합니다.
'Books > 스프링5 프로그래밍 입문' 카테고리의 다른 글
[Spring] @Transactional을 통한 트랜잭션 처리 (0) | 2021.03.22 |
---|---|
[Spring] 스프링 MVC 시작하기 (0) | 2021.03.20 |
[Spring] AOP (1) (0) | 2021.03.13 |
[Spring] Proxy 객체 (0) | 2021.03.12 |
[Spring] 빈의 라이프 사이클 (0) | 2021.03.10 |
- Total
- Today
- Yesterday
- 세그먼트트리
- Segment tree
- SCC
- Oracle
- 스위핑
- 정렬
- dfs
- DP
- Suffix Array
- hld
- Fenwick
- 이분탐색
- union find
- spring boot
- greedy
- bfs
- knapsack
- string
- dijkstra
- implementation
- sorting
- sweeping
- 좌표압축
- 2-SAT
- kmp
- 트라이
- 동적계획법
- spring
- 펜윅트리
- 이분매칭
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |