Spring Kotlin DSL: получить все бобы определенного типа
Предположим, у меня есть интерфейс Yoyo
и различные реализации этого интерфейса:
interface Yoyo {
fun haha() {
println("hello world")
}
}
@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 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)
}
Вместо того, чтобы вручную получать ref для всех bean-компонентов (что довольно утомительно), я хотел бы сделать это:
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
Я знаю, что мог бы сделать это вместо этого, но вместо этого я хотел бы использовать новый DSL Kotlin:
@Component
class Hoho : CommandLineRunner {
@Autowired
lateinit var list: List<Yoyo>
override fun run(vararg args: String?) {
list.forEach { it.haha() }
}
}
Является ли это возможным? Есть идеи?
PS Вот суть.
2 ответа
ref
Функция, используемая в DSL, может быть найдена здесь в источнике фреймворка. Не существует эквивалента для получения всех бинов типа, но вы можете добавить свое собственное расширение к BeanDefinitionDsl
класс для этого:
inline fun <reified T : Any> BeanDefinitionDsl.refAll() : Map<String, T> {
return context.getBeansOfType(T::class.java)
}
Единственная проблема в том, что context
требуется для этого internal
в текущей выпущенной версии фреймворка. Эта фиксация, сделанная 8 дней назад, делает ее общедоступной "для расширенных сценариев использования", но с тех пор не было выпущено новой версии фреймворка, поэтому она пока недоступна.
(Тот же коммит также заставляет класс расширять непосредственно BeanDefinitionDsl
класс а не BeanDefinitionDsl.BeanDefinitionContext
.)
Вывод: вам, вероятно, придется подождать следующего релиза, включающего коммит, упомянутый выше, и тогда вы сможете создать это расширение для себя. Я также отправил запрос на удаление в надежде, что он может быть включен в сам фреймворк.
context
упомянутый в предыдущем ответе @zsmb13 был оставлен internal
в пользу provider<Any>()
функция (начиная с весны 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)
}