Programming/Spring framework

스프링의 프록시 생성방식과 적용 실제 main 함수 사례. 2021-06-08

최동훈1 2021. 6. 8. 17:37

우선 이전 포스트의 빈 설정 클래스를 보자.

@Configuration
@EnableAspectJAutoProxy
public class Appctx {
	@Bean
	public ExeTimeAspect exeTimeAspect() {
		return new ExeTimeAspect();
	}
	
	@Bean
	public Calculator calculator() {
		return new RecCalculator();
	}
	

}

이렇게 빈 객체 설정을 완료한 후, 대상객체를 calculator(), 프록시를 exeTimeAspect()로 하는 스프링 AOP를 실제로 main 메서드에 적용해서 함수의 작동시간을 알아보는 코드를 보자.

public class MainAspect {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		AnnotationConfigApplicationContext ctx = 
				new AnnotationConfigApplicationContext(Appctx.class);

		Calculator cal = ctx.getBean("calculator", Calculator.class);
		long fiveFact = cal.factorial(5);
		System.out.println("cal.factorial(5) = " + fiveFact);
		System.out.println(cal.getClass().getName());
		ctx.close();

	}

}

이것을 실행해 보면 자바 콘솔 창에는 이런 값이 나온다.

RecCalculator.factorial([5]) 실행 시간 : 0 ns
cal.factorial(5) = 120
com.sun.proxy.$Proxy17
6월 08, 2021 3:48:40 오후 org.springframework.context.support.AbstractApplicationContext doClose
정보: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5387f9e0: startup date [Tue Jun 08 15:48:40 KST 2021]; root of context hierarchy


여기서 든 의문이 들 수 있다. 분명 System.out.println(cal.getClass().getName()); 을 하게 되면 Calcuator 타입이 RecCalculator 클래스가 아니고, $Proxy 가 나온 것이다. 분명 빈설정 클래스에는 "calculator" 빈 식별자로 getBean을 하면, RecCalculator 타입을 리턴하도록 만들었는데 말이다.
AOP를 적용하지 않았으면( 빈설정 클래스에서 ExeTimeAspect 클래스 전체를 주석처리하면, $Proxy가 아닌, RecCalculator 클래스 타입이 출력됨을 볼 수 있다.

이를 통해 우리가 알 수 있는 것은, AOP를 적용시킨 컨테이너에 getBean 메서드를 통해 빈 객체를 받아오면,(만약 받아오는 객체의 타입이 Pointcut에 정의된 범위라면, ex) "execution(public * chap07..*(..))") : chap07패키지나 그 하위 패키지에 속한 빈 객체) 스프링이 프록시 객체를 자동으로 생성해서 반환한다는 것이다. 애초에 스프링 AOP를 쓰는 이유가 프록시 객체를 자동 생성해서 돌리기 위함이다.
그런데 어떻게 $Proxy 클래스를 Calculator 클래스로 받을 수 있을까? 바로 $Proxy 클래스는 Calculator 클래스를 상속하는 클래스이여야만 다형성의 원리를 이용해서 Calculator 참조변수로 받을 수 있다. 애초에 프록시의 먹

스프링은 AOP를 위한 프록시 객체를 생성할 때 실제 생성할 빈 객체가 인터페이스를 상속하면 그 등록된 빈 객체가 상속받은 인터페이스를 이용해서 프록시를 생성한다.
왜 스프링이 이런 과정을 거쳐서까지 프록시 객체를 대상 빈객체의 인터페이스를 상속시키며 생성하는지 생각해 보았는데,  애초에 프록시의 본질적인 목적을 생각해 보자 ,


바로 공통의 기능을 뽑아내서 핵심기능을 "갈아끼울수 있게" 구조적인 프로그래밍을 위한 기능이다.

  즉, 위 코드에는 RecCalculator 클래스에 구현된 calculator() 메서드의 실행시간을 알고싶었다면, Caclulator 인터페이스를 상속받은 팩토리얼을 계산하는 기능을 가진 다른 클래스인 ImeCalculator 을 핵심기능으로 사용할려면 @Bean 설정 클래스에서 같은 인터페이스를 상속받을수 있으므로, 쉽게 바꿀수 있다. 또한, 실제 aop를 수행할 main 클래스에서 빈객체로 등록된 프럭시객체를 getBean 메서드를 통해 받아올때도, 참조변수를 상속받은 인터페이스인 Calculator로 받을수 있어서 쉽게 갈아끼울수 있다.  

page 167 공부완료.
공부시간 3시간
순공부시간 40분.

공부의 순도를 더더욱 높이자. 오늘은 마치고 운동갔다가 피자먹고싶다.