프록시 생성 방식
스프링 AOP에서 프록시를 생성할 때, 어떤 방식으로 프록시를 생성하는지는 해당 클래스가 인터페이스를 구현하고 있는지 여부에 따라 달라집니다.
- JDK 동적 프록시 (JDK Dynamic Proxy)
- 조건: 클래스가 하나 이상의 인터페이스를 구현하고 있는 경우, 스프링은 기본적으로 JDK 동적 프록시를 사용합니다.
- 동작 방식: JDK 동적 프록시는 인터페이스를 기반으로 프록시를 생성합니다. 이 프록시는 인터페이스의 모든 메서드를 구현하며, 실제로는 프록시가 메서드를 호출할 때 타겟 객체의 해당 메서드를 호출하게 됩니다.
- 특징: 프록시는 인터페이스를 구현하므로, 해당 프록시는 인터페이스 타입으로 캐스팅할 수 있지만, 구체적인 클래스 타입으로는 캐스팅할 수 없습니다.
- CGLIB 프록시
- 조건: 클래스가 인터페이스를 구현하지 않고 있는 경우, 스프링은 CGLIB을 사용하여 클래스 기반 프록시를 생성합니다.
- 동작 방식: CGLIB은 바이트코드 생성 라이브러리로, 구체적인 클래스를 상속받아 프록시 객체를 생성합니다. 이 프록시는 타겟 클래스의 서브클래스 역할을 하며, 타겟 메서드의 호출을 가로채서 부가 기능을 추가합니다.
- 특징: CGLIB 프록시는 클래스 기반이므로, 해당 프록시는 구체적인 클래스 타입으로 캐스팅할 수 있습니다. 또한,
final
메서드는 오버라이딩할 수 없기 때문에, CGLIB 프록시에서는 final
메서드에 대한 AOP 적용이 불가능합니다.
@Aspect
와 프록시 생성
@Aspect
애노테이션을 사용하여 AOP를 설정하고, 메서드에 특정 애노테이션을 적용할 때, 스프링은 자동으로 프록시 객체를 생성합니다.
- 이때 프록시 생성 방식은 위에서 설명한 것처럼 클래스의 인터페이스 구현 여부에 따라 결정됩니다.
- 즉, 메서드가 선언된 클래스가 인터페이스를 구현하고 있으면 JDK 동적 프록시가 사용되고, 인터페이스 없이 클래스만 있다면 CGLIB 프록시가 사용됩니다.
@EnableAspectJAutoProxy
설정
- 스프링의 기본 동작을 변경하고 싶을 때는
@EnableAspectJAutoProxy
애노테이션을 사용할 수 있습니다.
proxyTargetClass = true
로 설정하면 인터페이스를 구현하고 있는 클래스라도 CGLIB 프록시를 사용하도록 강제할 수 있습니다.
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
// 설정 클래스
}
이 설정은 CGLIB 프록시를 선호하거나 클래스 타입 캐스팅이 필요한 경우에 유용합니다.
요약
- 클래스가 인터페이스를 구현하고 있으면 JDK 동적 프록시를 사용하며, 그렇지 않으면 CGLIB 프록시를 사용합니다.
@EnableAspectJAutoProxy(proxyTargetClass = true)
를 사용하면 인터페이스를 구현한 클래스에도 CGLIB 프록시를 사용할 수 있습니다.