not eligible for getting processed by all BeanPostProcessors 경우 문제 해결
해당 Post는 사이드 프로젝트를 하다가 “not eligible for getting processed by all BeanPostProcessors” 경우가 있었습니다.
warning
으로 실제적인 에러는 아니기에 실행 시 중단되거나 하지는 않지만 이를 해결하는 방법을 정리했습니다.
"Bean '어떤Bean' of type [...] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)"
위와 같은 경고성 문구가 발생하는 경우가 있습니다.
가정
환경은 다음과 같이 가정합니다.
버전: Spring Boot 3.2, Spring Framework 6.1
예를 들어, 두 개의 Bean CircularDependencyA와 CircularDependencyB가 서로를 참조하는 순환 의존성이 발생했다고 가정합니다.
// Java 예시 (baeldung에서 제공한 순환 의존성 발생 코드)
@Component
public class CircularDependencyA {
private CircularDependencyB circB;
@Autowired
public CircularDependencyA(CircularDependencyB circB) {
this.circB = circB;
}
}
@Component
public class CircularDependencyB {
private CircularDependencyA circA;
@Autowired
public CircularDependencyB(CircularDependencyA circA) {
this.circA = circA;
}
}
// Kotlin 예시 (baeldung에서 제공한 순환 의존성 발생 코드를 변형)
@Component
class CircularDependencyA(private val circB: CircularDependencyB)
@Component
class CircularDependencyB(private val circA: CircularDependencyA)
이런 설정에서 애플리케이션이 시작될 때, Spring은 Bean을 생성하려다 순환 때문에 실패하거나 경고를 띄웁니다.
특히, AOP나 트랜잭션 같은 BeanPostProcessor가 적용되지 않아 “not eligible” 메시지가 로그에 나타납니다.
원인: 왜 이 경고가 발생할까?
원인1. 순환 의존성(Circular Dependencies)
Bean CircularDependencyA가 Bean CircularDependencyB를 의존하고,
Bean CircularDependencyB가 다시 Bean CircularDependencyA를 의존하는 경우 Spring은 생성 순서를 결정하지 못합니다.
Spring이 Bean을 생성하려 할 때, 의존성을 주입하기 전에 이미 다른 Bean이 필요해지기 때문입니다.
결과적으로, Bean이 완전히 초기화되지 않아 AOP auto-proxying 같은 BeanPostProcessor가 적용되지 않습니다.
A circular dependency occurs when a bean A depends on another bean B, and the bean B depends on bean A as well: Bean A → Bean B → Bean A.
참고 근거1: Baeldung - Circular Dependencies in Spring
원인2. BeanPostProcessor의 초기화 순서 문제
BeanPostProcessor 자체가 다른 Bean을 참조하거나, 의존성을 가질 때 발생합니다.
Spring은 BeanPostProcessor를 애플리케이션 컨텍스트 시작 초기에 인스턴스화합니다.
이 과정에서 참조되는 Bean들은 나중에 적용되는 BeanPostProcessor(예: auto-proxying)를 받을 수 없습니다.
For any such bean, you should see an informational log message: Bean someBean is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying).
참고 근거2: Spring Framework 공식 문서 - Container Extension Points
해결 방안
순환 의존성을 제거하는 식이면 좋겠지만, @Lazy 어노테이션을 사용해 지연 초기화를 적용하는 것을 공식문서에서도 권장한다.
Java에서의 해결
- @Lazy 사용: 의존성을 지연 초기화하여 프록시를 생성합니다. Bean이 실제로 필요할 때 초기화됩니다.
@Component
public class CircularDependencyA {
private CircularDependencyB circB;
@Autowired
public CircularDependencyA(@Lazy CircularDependencyB circB) {
this.circB = circB;
}
}
@Component
public class CircularDependencyB {
private CircularDependencyA circA;
@Autowired
public CircularDependencyB(CircularDependencyA circA) {
this.circA = circA;
}
}
- Setter Injection으로 전환: Constructor 대신 setter를 사용해 Bean을 먼저 생성한 후 의존성을 주입합니다. (Spring 문서에서 제안하는 방법)
@Component
public class CircularDependencyA {
private CircularDependencyB circB;
@Autowired
public void setCircB(@Lazy CircularDependencyB circB) {
this.circB = circB;
}
public CircularDependencyB getCircB() {
return circB;
}
}
Kotlin에서의 해결
- Kotlin은 immutable한 constructor injection을 선호하지만, 순환 시 lateinit var이나 @Lazy를 사용합니다.
- @Lazy 사용: Java와 유사하게 constructor에 적용합니다.
@Component
class CircularDependencyA(@Lazy private val circB: CircularDependencyB)
@Component
class CircularDependencyB(private val circA: CircularDependencyA)
- lateinit var와 Setter Injection: 필드를 lateinit으로 선언하고 setter로 주입합니다.
@Component
class CircularDependencyA {
lateinit var circB: CircularDependencyB
@Autowired
fun setCircB(@Lazy circB: CircularDependencyB) {
this.circB = circB
}
}
참고 근거3: Medium - Spring Circular Dependencies with @Lazy
참고 근거4: Baeldung 문서