Kotlin+Spring自定义Bean配置出现NullPointerException问题求助
Kotlin+Spring手动配置Bean触发NullPointerException问题解决
问题核心
手动通过@Configuration配置UserFacade Bean时,UserFactory实例为null,调用createCommon方法抛出NPE,但用@Service等注解或Java实现则正常。
原因分析
- Kotlin类默认final特性:
UserFactory默认是final类,Spring为UserFacade(标记为open)生成CGLIB代理时,无法对final类型的userFactory字段进行正确的代理初始化,导致字段为null。 - 手动实例化未纳入Spring管理:直接在
@Bean方法中new UserFactory,该实例未被Spring容器管理,结合代理机制,出现字段未赋值的情况。
解决方案
方案1:将UserFactory标记为open类
让Spring可以为UserFactory生成代理,确保代理对象的字段能正确初始化:
open class UserFactory( private val passwordEncoder: PasswordEncoder, private val userRepository: UserRepository ) { fun createCommon(username: String, password: String): User { // 实现逻辑 } }
方案2:将UserFactory声明为Spring Bean
把UserFactory也纳入Spring容器管理,通过依赖注入传入UserFacade,而非手动实例化:
@Configuration class UserConfig { @Bean fun userFacade( userRepository: UserRepository, passwordEncoder: PasswordEncoder, userFactory: UserFactory ): UserFacade = UserFacade(userRepository, passwordEncoder, userFactory) @Bean fun userFactory( passwordEncoder: PasswordEncoder, userRepository: UserRepository ): UserFactory = UserFactory(passwordEncoder, userRepository) @Bean fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder() }
方案3:关闭UserFacade的代理
如果UserFacade不需要被代理(比如没有AOP需求),去掉open关键字让它成为final类,Spring不会生成代理,直接使用原始实例,字段会正确赋值:
class UserFacade( private val userRepository: UserRepository, private val passwordEncoder: PasswordEncoder, private val userFactory: UserFactory ) { fun registerUser(dto: RegisterUserDTO): UserDTO { val user = userFactory.createCommon(dto.username, dto.password) return userRepository.save(user).toDTO() } }
为什么@Service方式正常?
使用@Service等注解时,Spring会自动处理Bean的创建、注入和代理逻辑,针对Kotlin的final类构造函数注入有专门的适配,避免了手动配置时的代理初始化问题。
内容的提问来源于stack exchange,提问作者Sampeteq
相关产品推荐
相关产品推荐

