Spring 3.1, CGLib에 의한 BeanCreationException 문제

Hansu Park·2023년 11월 29일
1

도입

Spring 3.1 환경에 있는 프로젝트를 진행하던 중 생성자주입 방식을 사용하자 에러가 났다. 대부분의 코드에서 필드주입을 대신하여 사용하고 있었고, 생성자주입 대신 필드주입을 사용하니 에러가 해결되었다. 왜 이러한 에러가 났는지 조사해보았다.

CGLIB 프록시의 문제점

현재 spring 3.1인  환경에서는 

  1. default 생성자가 필요한 점
  2. final을 사용할 수 없는 점
  3. 생성자를 이중호출 한다는 점

의 문제가 있다.

특히 프록시 되는 객체에 default 생성자가 없는 경우 생성자 주입 방식을 사용하면 에러[1]가 발생한다.

spring 4 이상의 버전에서는 문제가 해결되었다고 한다. 자세한 내용은 참고

(참고: https://code-lab1.tistory.com/193 ), 

그렇다면 왜 생성자 주입 방식으로 만든 객체도 존재하는가?

AOP에 등록되지 않아 프록시가 만들어지지 않았기 때문이다. 혹은 인터페이스가 존재하여 CGLIB 대신 jdk-proxy가 활용되는 경우이다.

(실제로 해당 객체에 @Transactional 키워드를 붙이니 에러가 발생한다.)

※모든 스프링 빈이 프록싱되는 것은 아니다.

(참고: 문제해결에 도움을 받은 문서

default 생성자를 추가하면 되지 않을까?

추가하면 생성자 주입을 활용할 수 있다. 하지만 아래와 같은 이유로 default 생성자 + 생성자 주입 대신 기존의 방식대로 필드 주입을 사용하기로 결정했다.

  1. final 키워드를 붙일 수 없다는 점.
  • 생성자 주입의 장점 퇴색.
  1. 테스트 코드를 사용하지 않는다는 점.
  • 필드 주입의 단점 상쇄.
  1. 불필요한 default 생성자가 추가된다는 점.

[1] 발생한 에러

| org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'XXXController' defined in ~\XXXController.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class XXXController]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:638) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:942) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482) at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:651) at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:602) at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:665) at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:521) at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:462) at
| --- |

0개의 댓글