스프링에서 final 사용 시 CGLIB 문제와 NPE 예방

스프링에서 final을 쓰면 안되는 이유 (feat. CGLIB)

카테고리

프로그래밍/소프트웨어 개발

서브카테고리

개발 툴

대상자 대상자_정보 출력

  • Spring 프레임워크 사용자 (특히 AOP, 프록시 기반 개발자)
  • 중급 이상 Java 개발자 (프록시 메커니즘 이해 필요)
  • 실무에서 @Repository/@Component 사용자

핵심 요약

  • @Repository로 선언한 클래스에 final을 붙이면 CGLIB 프록시 생성 실패 -> Null Pointer Exception 발생
  • final 메서드는 프록시로 래핑되지 않아 필드 참조 시 null 발생 -> 예상치 못한 NPE 발생
  • @Component 대신 @Repository 사용 시 프록시 생성 차이로 동작 불일치 -> AOP 적용 범위 차이

섹션별 세부 요약

###1. 문제 상황

  • @Repository 사용 시 NPE 발생, @Component 사용 시 정상
  • ReservationRepositorydao 필드가 null로 초기화
  • 생성자에서는 정상 주입, 메서드 호출 시 null 발생

###2. 프록시 메커니즘

  • Spring AOP는 JDK Dynamic Proxy/CGLIB Proxy 사용
  • CGLIB는 final 클래스/메서드를 상속 불가능 -> 프록시 생성 실패
  • CGLIB 프록시는 원본 객체를 MethodInterceptor로 접근 -> 필드 초기화 시 null

###3. final 메서드의 문제

  • final 메서드는 프록시에 래핑되지 않음
  • 프록시 객체의 final 메서드 호출 시 실제 필드가 초기화되지 않음 -> NPE 발생
  • 예: finalMethod() 호출 시 this.dao가 null

###4. 해결 및 예방

  • final 키워드를 클래스/메서드에 사용하지 않도록 권장
  • @Component 대신 @Repository 사용 시 AOP 적용 범위 차이 주의
  • @Transactional 메서드에 final 사용 시 트랜잭션 적용 실패

결론

  • Spring 빈에 final 키워드 사용은 프록시 생성을 방해 -> NPE 발생 가능성
  • CGLIB 프록시 메커니즘 이해 필수 (Spring 6.2.5 기준)
  • AOP 적용 대상 메서드에 final 사용은 피하고, @Component보다 @Repository 사용 시 주의