spring 引导启动过程失败,lateinit var 未初始化:DI 问题
spring boot startup process failed with lateinit var not initialized : DI Issue
我正在构建一个后端,它将从几个外部 API 获取一些数据,在一些进程之后填充数据库,然后通过 rest api 公开这些数据。在 springboot 中使用 JPA 和 postgresql。
我已经创建了实体、存储库并从网络客户端获取外部 api。
但是,我有一个依赖注入问题。我阅读了大量文章和问题,但无法使其正常工作。尝试注入存储库时,我遇到了众所周知的错误 lateinit var not initialized
。
我也试过构造函数注入,但还是不行。似乎存储库不被认为是可以自动装配的 bean。
如有任何帮助,我们将不胜感激
已修复 请参阅下面的解决方案。 PB 在职
申请。 运行 来自上下文的启动进程
@SpringBootApplication(exclude = [JacksonAutoConfiguration::class])
class SpringbootkotlinApplication
fun main(args: Array<String>) {
val context = runApplication<SpringbootkotlinApplication>(*args)
val startupProcess = context.getBean(StartupProcesses::class.java)
startupProcess.fetchGroup()
}
startup class as @component :fetches external api 并调用服务将数据保存在 db
@Component
class StartupProcesses {
fun fetchGroup() {
val fetch = IronMaidenSourceApi.fetchIronMaidenSource() //<-- fetch ext api OK
SplitDataSourceToEntities().populateGroup(fetch) //<-- call service to populate db
}
}
应该通过存储库填充数据库但在 lateinit 存储库中出错的服务
@Service
class SplitDataSourceToEntities {
@Autowired
lateinit var repo:IronMaidenGroupRepository // <-- error is here
fun populateGroup(dto: DTOIronMaidenAPi): IronMaidenGroupEntity {
val dbgroup = IronMaidenGroupEntity(
groupId = dto.id!!,
name = dto.name ?: ""
)
return repo.save(dbgroup)
}
}
repo,扩展 JPA 存储库
import com.jerome.springbootkotlin.model.dbentities.ironmaidengroupentity.IronMaidenGroupEntity
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface IronMaidenGroupRepository:JpaRepository<IronMaidenGroupEntity, String> {
}
解决方案
服务应该这样定义(SplitDataSourceToEntitiesclass 也应该late init
而不是被实例化)
@Component
class StartupProcesses {
@Autowired
lateinit var splitDataSourceToEntities: SplitDataSourceToEntities // <--add this lateinit
fun fetchGroup() {
val fetch = IronMaidenSourceApi.fetchIronMaidenSource()
splitDataSourceToEntities.populateGroup(fetch) //<-- fix is here
}
}
@Autowired 仅在由 Spring
管理时有效
值得注意的是,@Autowired
仅在 class 已被 Spring 初始化时才有效。在您的代码中,您在 class SplitDataSourceToEntities
中有一个 @Autowired
注释,但是您在 StartupProcesses.fetchGroup
中手动实例化了 SplitDataSourceToEntities
。那行不通,因为 Spring 不可能 auto-wire lateinit var
.
使用您的服务的自动装配实例可以轻松解决该问题:
@Component
class StartupProcesses {
@Autowired
lateinit var splitDataSourceToEntities: SplitDataSourceToEntities
fun fetchGroup() {
val fetch = IronMaidenSourceApi.fetchIronMaidenSource() //<-- fetch ext api OK
splitDataSourceToEntities.populateGroup(fetch) //<-- call service to populate db
}
}
帮助Spring找到你的JpaRepository
此外,您可能需要向您的应用程序添加一个 @EnableJpaRepositories
注释:
@EnableJpaRepositories(basePackageClasses = [IronMaidenGroupRepository::class])
@SpringBootApplication(exclude = [JacksonAutoConfiguration::class])
class SpringbootkotlinApplication
...
您可以直接通过名称定义包,而不是 basePackageClasses = ...
,但是您的示例中不包含包名。
你必须使用@Autowired吗?
正在考虑您在评论中提出的问题:
你的设计没有错,因为@Component
和@Autowired
不是没有必要去“玩”。您也可以去掉 @Autowired
注释并将这些变量定义为构造函数参数等。
可能看起来像这样:
class SpringbootkotlinApplication
fun main(args: Array<String>) {
val context = runApplication<SpringbootkotlinApplication>(*args)
val repo = context.getBean(IronMaidenGroupRepository::class.java)
StartupProcesses(SplitDataSourceToEntities(repo))
}
@Component
class StartupProcesses(
val splitDataSourceToEntities: SplitDataSourceToEntities
) {
...
}
@Service
class SplitDataSourceToEntities(
val repo: IronMaidenGroupRepository
) {
...
}
现在只有 Repository
由 Spring 管理,但在 flip-side 上,您必须自己管理其他所有内容,当您的 class 时,这可能会变得非常乏味es 和它们的依赖性增长。只让 Spring 管理所有依赖关系会更舒服(并最终导致更好的可读代码)。
我正在构建一个后端,它将从几个外部 API 获取一些数据,在一些进程之后填充数据库,然后通过 rest api 公开这些数据。在 springboot 中使用 JPA 和 postgresql。
我已经创建了实体、存储库并从网络客户端获取外部 api。
但是,我有一个依赖注入问题。我阅读了大量文章和问题,但无法使其正常工作。尝试注入存储库时,我遇到了众所周知的错误 lateinit var not initialized
。
我也试过构造函数注入,但还是不行。似乎存储库不被认为是可以自动装配的 bean。
如有任何帮助,我们将不胜感激
已修复 请参阅下面的解决方案。 PB 在职
申请。 运行 来自上下文的启动进程
@SpringBootApplication(exclude = [JacksonAutoConfiguration::class])
class SpringbootkotlinApplication
fun main(args: Array<String>) {
val context = runApplication<SpringbootkotlinApplication>(*args)
val startupProcess = context.getBean(StartupProcesses::class.java)
startupProcess.fetchGroup()
}
startup class as @component :fetches external api 并调用服务将数据保存在 db
@Component
class StartupProcesses {
fun fetchGroup() {
val fetch = IronMaidenSourceApi.fetchIronMaidenSource() //<-- fetch ext api OK
SplitDataSourceToEntities().populateGroup(fetch) //<-- call service to populate db
}
}
应该通过存储库填充数据库但在 lateinit 存储库中出错的服务
@Service
class SplitDataSourceToEntities {
@Autowired
lateinit var repo:IronMaidenGroupRepository // <-- error is here
fun populateGroup(dto: DTOIronMaidenAPi): IronMaidenGroupEntity {
val dbgroup = IronMaidenGroupEntity(
groupId = dto.id!!,
name = dto.name ?: ""
)
return repo.save(dbgroup)
}
}
repo,扩展 JPA 存储库
import com.jerome.springbootkotlin.model.dbentities.ironmaidengroupentity.IronMaidenGroupEntity
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface IronMaidenGroupRepository:JpaRepository<IronMaidenGroupEntity, String> {
}
解决方案
服务应该这样定义(SplitDataSourceToEntitiesclass 也应该late init
而不是被实例化)
@Component
class StartupProcesses {
@Autowired
lateinit var splitDataSourceToEntities: SplitDataSourceToEntities // <--add this lateinit
fun fetchGroup() {
val fetch = IronMaidenSourceApi.fetchIronMaidenSource()
splitDataSourceToEntities.populateGroup(fetch) //<-- fix is here
}
}
@Autowired 仅在由 Spring
管理时有效值得注意的是,@Autowired
仅在 class 已被 Spring 初始化时才有效。在您的代码中,您在 class SplitDataSourceToEntities
中有一个 @Autowired
注释,但是您在 StartupProcesses.fetchGroup
中手动实例化了 SplitDataSourceToEntities
。那行不通,因为 Spring 不可能 auto-wire lateinit var
.
使用您的服务的自动装配实例可以轻松解决该问题:
@Component
class StartupProcesses {
@Autowired
lateinit var splitDataSourceToEntities: SplitDataSourceToEntities
fun fetchGroup() {
val fetch = IronMaidenSourceApi.fetchIronMaidenSource() //<-- fetch ext api OK
splitDataSourceToEntities.populateGroup(fetch) //<-- call service to populate db
}
}
帮助Spring找到你的JpaRepository
此外,您可能需要向您的应用程序添加一个 @EnableJpaRepositories
注释:
@EnableJpaRepositories(basePackageClasses = [IronMaidenGroupRepository::class])
@SpringBootApplication(exclude = [JacksonAutoConfiguration::class])
class SpringbootkotlinApplication
...
您可以直接通过名称定义包,而不是 basePackageClasses = ...
,但是您的示例中不包含包名。
你必须使用@Autowired吗?
正在考虑您在评论中提出的问题:
你的设计没有错,因为@Component
和@Autowired
不是没有必要去“玩”。您也可以去掉 @Autowired
注释并将这些变量定义为构造函数参数等。
可能看起来像这样:
class SpringbootkotlinApplication
fun main(args: Array<String>) {
val context = runApplication<SpringbootkotlinApplication>(*args)
val repo = context.getBean(IronMaidenGroupRepository::class.java)
StartupProcesses(SplitDataSourceToEntities(repo))
}
@Component
class StartupProcesses(
val splitDataSourceToEntities: SplitDataSourceToEntities
) {
...
}
@Service
class SplitDataSourceToEntities(
val repo: IronMaidenGroupRepository
) {
...
}
现在只有 Repository
由 Spring 管理,但在 flip-side 上,您必须自己管理其他所有内容,当您的 class 时,这可能会变得非常乏味es 和它们的依赖性增长。只让 Spring 管理所有依赖关系会更舒服(并最终导致更好的可读代码)。