관리 메뉴

진취적 삶

7.4 프록시 생성 방식 본문

스프링 5 프로그래밍 입문/7. AOP 프로그래밍

7.4 프록시 생성 방식

hp0724 2023. 9. 6. 00:11

스프링은 AOP 를 위한 프록시 객체를 생성할 때 실제 생성할 빈 객체가 인터페이스를 상속하면

인터페이스를 이용해서 프록시를 생성한다.

RecCalculator 클래스가 calculator 인터페이스를 상속하므로 ,

calculator 인터페이스를 상속받은 프록시 객체를 생성

인터페이스가 아닌 클래스를 이용해서 프록시를 생성하고 싶다면

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass =true) 
public class AppCtx {

7.4.1 execution 명시자 표현식

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

execution 명시자는 Advice를 적용할 메서드를 지정할 때 사용한다.

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

  • 수식어 패턴 은 생략 가능 public, protected 등이 온다. 스프링 AOP는 public 메서드만 가능
  • 리턴타입패턴 은 리턴 타입 명시
  • 각 패턴은 * 을 아용하여 모든 값을 표현 할수 있다.
설명
execution(public void set*(..)) 리턴 타입 void 메서드 이름 set
파라미터가 0 개 이상
execution(* chap07 ,,()) chop07 패키지 타입에 속한 파라미터가 없는 모드 메서드

7.4.2 Advice 적용 순서

@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("Cache에서 구함[%d]\n",num);
			return cache.get(num);
		}
		Object result = joinPoint.proceed();
		cache.put(num,result);
		System.out.printf("Cache에서 추가 [%d]\n",num);
		return result;
	}
	
}
  • Long num =(Long) joinPoint.getArgs()[0]; 첫번째 인자를 Long 타입으로 구하기
  • if(cache.containsKey(num)) { System.out.printf("Cache에서 구함[%d]\n",num); return cache.get(num); } 캐시에 해당 값이 있으면 리턴
  • Object result = joinPoint.proceed() cache에 존재하지 않으면 프록시 대상 객체 실행
  • cache.put(num,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();
	}
}
public class MainAspectWithCache {

	public static void main(String[] args) {
		
		AnnotationConfigApplicationContext ctx =new AnnotationConfigApplicationContext(AppCtxWithCache.class);
		
		Calculator cal =ctx.getBean("calculator",Calculator.class);
		cal.factorial(7);
		cal.factorial(7);
		cal.factorial(5);
		cal.factorial(5);
		ctx.close();

	}

}

CacheAspect 프록시 → ExeTimeAspect프록시 → 실제 대상 객체

CacheAspect 는 cache 맵에 데이터가 존재하지 않으면 joinPoint.preceed() 실행

그 대상이 ExeTimeAspect 이므로 ExeTimeAspect의 measure()메서드 실행

ExeTimeAspect 실제 대상 객체 실행하고 콘솔에 실행 시간 출력

ExeTimeAspect 실행이 끝나면 CacheAspect는 cache 맵에 데이터를 넣고

콘솔에 cache추가 메시지 출력

두번째 호출시에는 데이터가 존재하기 때문에 containsKey에서 true를 리턴하므로

콘솔에 cache에서 구함이 나온다.

적용순서가 중요하다면 직접 순서를 지정해야한다.

따라서 @Order 를 사용한다. @Aspect 와 함께 @Order 클래스에 붙이면 지정한 값에 따라

적용 순서를 결정한다.

@Order 값이 작은면 먼저 적용하고 크면 나중에 적용한다.

7.4.3 @Around 의 Pointcut 설정과 @Pointcut 재사용

@Around(execution(public * chap07..*(long))") 

'스프링 5 프로그래밍 입문 > 7. AOP 프로그래밍' 카테고리의 다른 글

7.1 프로젝트 준비  (0) 2023.09.06
7.2 프록시와 AOP  (0) 2023.09.06
7.3 스프링 AOP 구현  (0) 2023.09.06