Spring Kotlin DSL:获取特定类型的所有 bean
Spring Kotlin DSL: get all beans of certain type
假设我有一个接口 Yoyo
和这个接口的不同实现:
interface Yoyo {
fun haha() {
println("hello world")
}
}
@Component class Yoyo1 : Yoyo
@Component class Yoyo2 : Yoyo
@Component class Yoyo3 : Yoyo
@Component class YoyoN : Yoyo
现在我想实例化所有 bean 并在上下文初始化后做一些逻辑:
@SpringBootApplication
class YoyoApp
fun main(args: Array<String>) {
SpringApplicationBuilder()
.sources(YoyoApp::class.java)
.initializers(beans {
bean {
CommandLineRunner {
val y1 = ref<Yoyo1>()
val y2 = ref<Yoyo2>()
val y3 = ref<Yoyo3>()
val yN = ref<YoyoN>()
arrayOf(y1, y2, y3, yN).forEach { it.haha() }
}
}
})
.run(*args)
}
与其手动获取所有 bean 的 ref(这相当乏味),我想这样做:
val list = ref<List<Yoyo>>()
list.forEach { it.haha() }
但是我得到一个例外:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.List<?>' available
我知道我可以这样做,但我想改用新的 Kotlin DSL:
@Component
class Hoho : CommandLineRunner {
@Autowired
lateinit var list: List<Yoyo>
override fun run(vararg args: String?) {
list.forEach { it.haha() }
}
}
可能吗?有什么想法吗?
P.S。这是 gist.
DSL 中使用的ref
函数可以在here 框架的源代码中找到。获取一个类型的所有 bean 没有等价物,但您可以将自己的扩展添加到 BeanDefinitionDsl
class 来执行此操作:
inline fun <reified T : Any> BeanDefinitionDsl.refAll() : Map<String, T> {
return context.getBeansOfType(T::class.java)
}
唯一的问题是,在当前发布的框架版本中,为此所需的 context
是 internal
。 This commit from 8 days ago makes it publicly available "for advanced use-cases", but there hasn't been 框架的新版本,因此尚不可用。
(同样的提交也使得 class 直接扩展 BeanDefinitionDsl
class 而不是 BeanDefinitionDsl.BeanDefinitionContext
。)
结论:您可能必须等待包含上述提交的下一个版本,然后您才能为自己创建此扩展。我还提交了一个 pull request 希望这可以包含在框架本身中。
@zsmb13 在之前的回答中提到的 context
是 left internal
支持 provider<Any>()
功能(从 Spring 5.1. 1).所以最后我得到了以下结果:
interface Yoyo {
fun haha() {
println("hello world from: ${this.javaClass.canonicalName}")
}
}
@Component class Yoyo1 : Yoyo
@Component class Yoyo2 : Yoyo
@Component class Yoyo3 : Yoyo
@Component class YoyoN : Yoyo
@SpringBootApplication
class YoyoApp
fun main(args: Array<String>) {
SpringApplicationBuilder()
.sources(YoyoApp::class.java)
.initializers(beans {
bean {
CommandLineRunner {
val list = provider<Yoyo>().toList()
list.forEach { it.haha() }
}
}
})
.run(*args)
}
假设我有一个接口 Yoyo
和这个接口的不同实现:
interface Yoyo {
fun haha() {
println("hello world")
}
}
@Component class Yoyo1 : Yoyo
@Component class Yoyo2 : Yoyo
@Component class Yoyo3 : Yoyo
@Component class YoyoN : Yoyo
现在我想实例化所有 bean 并在上下文初始化后做一些逻辑:
@SpringBootApplication
class YoyoApp
fun main(args: Array<String>) {
SpringApplicationBuilder()
.sources(YoyoApp::class.java)
.initializers(beans {
bean {
CommandLineRunner {
val y1 = ref<Yoyo1>()
val y2 = ref<Yoyo2>()
val y3 = ref<Yoyo3>()
val yN = ref<YoyoN>()
arrayOf(y1, y2, y3, yN).forEach { it.haha() }
}
}
})
.run(*args)
}
与其手动获取所有 bean 的 ref(这相当乏味),我想这样做:
val list = ref<List<Yoyo>>()
list.forEach { it.haha() }
但是我得到一个例外:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.List<?>' available
我知道我可以这样做,但我想改用新的 Kotlin DSL:
@Component
class Hoho : CommandLineRunner {
@Autowired
lateinit var list: List<Yoyo>
override fun run(vararg args: String?) {
list.forEach { it.haha() }
}
}
可能吗?有什么想法吗?
P.S。这是 gist.
DSL 中使用的ref
函数可以在here 框架的源代码中找到。获取一个类型的所有 bean 没有等价物,但您可以将自己的扩展添加到 BeanDefinitionDsl
class 来执行此操作:
inline fun <reified T : Any> BeanDefinitionDsl.refAll() : Map<String, T> {
return context.getBeansOfType(T::class.java)
}
唯一的问题是,在当前发布的框架版本中,为此所需的 context
是 internal
。 This commit from 8 days ago makes it publicly available "for advanced use-cases", but there hasn't been 框架的新版本,因此尚不可用。
(同样的提交也使得 class 直接扩展 BeanDefinitionDsl
class 而不是 BeanDefinitionDsl.BeanDefinitionContext
。)
结论:您可能必须等待包含上述提交的下一个版本,然后您才能为自己创建此扩展。我还提交了一个 pull request 希望这可以包含在框架本身中。
@zsmb13 在之前的回答中提到的 context
是 left internal
支持 provider<Any>()
功能(从 Spring 5.1. 1).所以最后我得到了以下结果:
interface Yoyo {
fun haha() {
println("hello world from: ${this.javaClass.canonicalName}")
}
}
@Component class Yoyo1 : Yoyo
@Component class Yoyo2 : Yoyo
@Component class Yoyo3 : Yoyo
@Component class YoyoN : Yoyo
@SpringBootApplication
class YoyoApp
fun main(args: Array<String>) {
SpringApplicationBuilder()
.sources(YoyoApp::class.java)
.initializers(beans {
bean {
CommandLineRunner {
val list = provider<Yoyo>().toList()
list.forEach { it.haha() }
}
}
})
.run(*args)
}