Spring Boot Kotlin中BeanCreationException问题求助
Kotlin Spring Boot @Transactional 导致CGLIB代理失败问题解决
问题代码
SomeConfig.kt
@Configuration class SomeConfig { @Bean fun someServiceBean() = object : MyService { @Transactional override fun doWork(): String { return "Some work have been done" } } @Bean fun cliRunner(myService: MyService): CommandLineRunner = CommandLineRunner { myService.doWork() println(myService.doWork()) } }
MyService.kt
interface MyService { fun doWork(): String }
启动错误日志
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 2023-11-09T10:53:45.047+03:00 ERROR 22666 --- [ main] o.s.boot.SpringApplication : Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someServiceBean' defined in class path resource [ru/mindtable/config/SomeConfig.class]: Could not generate CGLIB subclass of class ru.mindtable.config.SomeConfig$someServiceBean$1: Common causes of this problem include using a final class or a non-visible class at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:605) ~[spring-beans-6.0.13.jar:6.0.13] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) ~[spring-beans-6.0.13.jar:6.0.13] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) ~[spring-beans-6.0.13.jar:6.0.13] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.13.jar:6.0.13] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) ~[spring-beans-6.0.13.jar:6.0.13] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-6.0.13.jar:6.0.13] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) ~[spring-beans-6.0.13.jar:6.0.13] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:950) ~[spring-context-6.0.13.jar:6.0.13] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) ~[spring-context-6.0.13.jar:6.0.13] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.1.5.jar:3.1.5] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:738) ~[spring-boot-3.1.5.jar:3.1.5] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:440) ~[spring-boot-3.1.5.jar:3.1.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) ~[spring-boot-3.1.5.jar:3.1.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-3.1.5.jar:3.1.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-3.1.5.jar:3.1.5] at ru.mindtable.config.TaskTrackerApplicationKt.main(TaskTrackerApplication.kt:13) ~[main/:na] Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class ru.mindtable.config.SomeConfig$someServiceBean$1: Common causes of this problem include using a final class or a non-visible class at org.springframework.aop.framework.CglibAopProxy.buildProxy(CglibAopProxy.java:222) ~[spring-aop-6.0.13.jar:6.0.13] at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:155) ~[spring-aop-6.0.13.jar:6.0.13] at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110) ~[spring-aop-6.0.13.jar:6.0.13] at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.buildProxy(AbstractAutoProxyCreator.java:517) ~[spring-aop-6.0.13.jar:6.0.13] at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:464) ~[spring-aop-6.0.13.jar:6.0.13] at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:369) ~[spring-aop-6.0.13.jar:6.0.13] at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:318) ~[spring-aop-6.0.13.jar:6.0.13] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:434) ~[spring-beans-6.0.13.jar:6.0.13] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1773) ~[spring-beans-6.0.13.jar:6.0.13] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598) ~[spring-beans-6.0.13.jar:6.0.13] ... 15 common frames omitted Caused by: java.lang.IllegalArgumentException: Cannot subclass final class ru.mindtable.config.SomeConfig$someServiceBean$1 at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:653) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:26) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.core.ClassLoaderAwareGeneratorStrategy.generate(ClassLoaderAwareGeneratorStrategy.java:57) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:366) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:575) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.lambda$new$1(AbstractClassGenerator.java:107) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.core.internal.LoadingCache.lambda$createEntry$1(LoadingCache.java:52) ~[spring-core-6.0.13.jar:6.0.13] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na] at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:57) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:130) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:317) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:562) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:407) ~[spring-core-6.0.13.jar:6.0.13] at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:62) ~[spring-aop-6.0.13.jar:6.0.13] at org.springframework.aop.framework.CglibAopProxy.buildProxy(CglibAopProxy.java:213) ~[spring-aop-6.0.13.jar:6.0.13] ... 24 common frames omitted
问题原因
Kotlin中匿名对象默认是final类,而Spring的@Transactional注解默认使用CGLIB代理实现事务增强,CGLIB需要生成目标类的子类来织入逻辑,final类无法被继承,因此报错。
解决方案
方案1:将匿名对象改为open的具名类
把匿名实现的MyService替换为显式的open类,允许Spring生成子类代理:
@Configuration class SomeConfig { open class MyServiceImpl : MyService { @Transactional override fun doWork(): String { return "Some work have been done" } } @Bean fun someServiceBean() = MyServiceImpl() @Bean fun cliRunner(myService: MyService): CommandLineRunner = CommandLineRunner { myService.doWork() println(myService.doWork()) } }
方案2:使用JDK动态代理替代CGLIB
通过配置让Spring使用基于接口的JDK动态代理,不需要子类化目标类:
- 在
application.properties中添加配置:
spring.aop.proxy-target-class=false
- 可将
@Transactional注解移到接口方法上(可选,增强可读性):
interface MyService { @Transactional fun doWork(): String }
方案3:使用@Transactional的proxyTargetClass属性(局部配置)
如果不想全局修改代理方式,可以在@Transactional注解中指定使用JDK代理:
@Transactional(proxyTargetClass = false) override fun doWork(): String { return "Some work have been done" }
内容的提问来源于stack exchange,提问作者Артем Жуйков
相关产品推荐
相关产品推荐

