【发布时间】:2017-07-24 16:25:04
【问题描述】:
我遇到了一个问题,即在调用 @Transactional 方法期间 bean 的属性变为空。
-
UserService是在@Configuration类中声明的 bean -
userRepository和passwordService在初始化期间不为空(afterPropertiesSet) - 在调用 registerUser(即
@Transactional)期间,这些属性变为空 - 这些属性具有不可为空的类型
- 已根据打印使用了相同的 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 { ... }
}
Bean 声明:
@Configuration
@EnableTransactionManagement
open class ApplicationServicesConfiguration {
@Bean
open fun userService(userRepository: UserRepository,
passwordService: PasswordService): UserService = UserService(userRepository, passwordService)
@Bean
open fun passwordService(passwordRepository: PasswordRepository): PasswordService = PasswordService(passwordRepository)
}
打印:
### 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
这是 Spring 错误吗?还是 Kotlin-Spring 集成的怪癖?
【问题讨论】:
-
你试过用
UserService注释@Service吗? -
我没有。但是我在
@Configuration类中将 UserService 声明为@Bean。为了清楚起见,添加了 bean 声明。 -
@BranislavLazic 按要求添加了包结构
-
对 Kotlin 不太熟悉,但
@Transactional fun似乎是最终版本。这使其不可代理,因此它将使用代理的实例(null)而不是调用实际包装的实例。尝试制作函数open。
标签: java spring spring-boot kotlin