티스토리 뷰

프록시 생성방식

스프링은 프록시를 생성할 때, 실제 생성할 빈 객체가 인터페이스를 상속하면 프록시 타입 또한 해당 인터페이스를 상속해서 만들어지게 됩니다. 즉 다음과 같은 코드는 오류가 발생합니다.

	//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)를 지정한 것과 동일합니다.

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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 29 30 31
글 보관함