Java 初始化期间不为null的Bean属性在@Transactional方法调用期间变为null

Java 初始化期间不为null的Bean属性在@Transactional方法调用期间变为null,java,spring,spring-boot,kotlin,Java,Spring,Spring Boot,Kotlin,我遇到了一个问题,在调用@Transactional方法期间,bean的属性变为null UserService是在@Configuration类中声明的bean userRepository和passwordService在初始化期间不为空(afterPropertiesSet) 在调用registerUser(即@Transactional)期间,这些属性将变为null 这些属性具有不可为空的类型 基于打印使用了UserService的相同实例/bean 删除@Transactional似

我遇到了一个问题,在调用
@Transactional
方法期间,bean的属性变为null

  • UserService
    是在
    @Configuration
    类中声明的bean
  • userRepository
    passwordService
    在初始化期间不为空
    (afterPropertiesSet)
  • 在调用registerUser(即
    @Transactional
    )期间,这些属性将变为null
  • 这些属性具有不可为空的类型
  • 基于打印使用了UserService的相同实例/bean
  • 删除
    @Transactional
    似乎可以解决这个问题
  • 添加或删除
    @EnableTransactionManagement
    似乎没有任何作用
服务:

open class UserService (val userRepository: UserRepository,
                        val passwordService: PasswordService) : InitializingBean {

    override fun afterPropertiesSet() {
        println("### this.afterPropertiesSet")
        println("### this: " + this)
        println("### userRepository: " + userRepository)
        println("### passwordService: " + passwordService)
    }

    @Transactional
    fun registerUser(request: UserRegistrationRequest): User {
        println("### this.registerUser")
        println("### this: " + this)
        println("### userRepository: " + userRepository)
        println("### passwordService: " + passwordService)
        val savedUser = this.userRepository.save(request.toUser())
        this.passwordService.savePassword(savedUser, request.password)
        return savedUser
    }

    private fun UserRegistrationRequest.toUser(): User { ... }

}
控制器:

@Controller
class UserController (val userService: UserService) : InitializingBean {
    override fun afterPropertiesSet() {
        println("### controller.afterPropertiesSet: " + userService)
        println("### user service: " + userService)
    }

    @PostMapping("/users")
    fun registerUser(@RequestBody userDetails: UserDetailsDto): ResponseEntity<UserDto> {
        println("### controller.registerUser: " + userService)
        println("### user service: " + userService)
        val registeredUser = userService.registerUser(userDetails.toUserRegistrationRequest())
        return ResponseEntity.ok(registeredUser.toDto())
    }

    private fun UserDetailsDto.toUserRegistrationRequest(): UserRegistrationRequest { ... }

    private fun User.toDto(): UserDto { ... }
}
印刷品:

### this.afterPropertiesSet
### this: com.sample.mojo.user.UserService@1ab14636
### userRepository: org.springframework.data.jpa.repository.support.SimpleJpaRepository@1961d75a
### passwordService: com.sample.mojo.user.PasswordService@36359723

### controller.afterPropertiesSet: com.sample.mojo.user.UserService@1ab14636
### user service: com.sample.mojo.user.UserService@1ab14636

### controller.registerUser: com.sample.mojo.user.UserService@1ab14636
### user service: com.sample.mojo.user.UserService@1ab14636

### this.registerUser
### this: com.sample.mojo.user.UserService@1ab14636
### userRepository: null
### passwordService: null
包结构

com.sample.app.Application
com.sample.app.ApplicationServicesConfiguration
com.sample.app.user.UserController
com.sample.app.user.UserService
com.sample.app.user.UserRepository
com.sample.app.user.PasswordService

这是弹簧虫吗?还是Kotlin Spring集成怪癖?

尝试将事务功能标记为打开

有一个gradle插件,用于将所有类标记为打开:

buildscript{
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
    }
}
apply plugin: 'kotlin-spring'

你试过用
@Service
注释
UserService
吗?我没有。但是我在
@配置
类中将UserService声明为
@Bean
。为清晰起见,添加了bean声明。@BranislavLazic根据请求添加了包结构对Kotlin不太熟悉,但
@Transactional fun
似乎是最终的。这使得它不可代理,因此它将使用代理的实例(即
null
)而不是调用实际包装的实例。尝试打开功能
buildscript{
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
    }
}
apply plugin: 'kotlin-spring'