2

假设我有一个接口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的引用(这很乏味),而是这样做:

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() }
    }
}

是否可以?有任何想法吗?

PS 这里是要点

4

2 回答 2

2

context@zsmb13 在上一个答案中提到的支持该功能( Spring 5.1.1 开始)。所以最后我得到了以下结果:internalprovider<Any>()

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)
}
于 2018-11-22T13:18:22.647 回答
1

DSL 中使用的ref函数可以框架的源代码中找到。获取一个类型的所有 bean 没有等价物,但您可以将自己的扩展添加到BeanDefinitionDsl类中来执行此操作:

inline fun <reified T : Any> BeanDefinitionDsl.refAll() : Map<String, T> {
    return context.getBeansOfType(T::class.java)
}

唯一的问题是,当前发布的框架版本context需要此功能。8 天前的这个提交使它公开可用“用于高级用例”,但从那以后还没有新版本的框架,所以它还不可用。internal

(同样的提交也使类直接扩展BeanDefinitionDsl类而不是BeanDefinitionDsl.BeanDefinitionContext。)


结论:您可能必须等待包含上述提交的下一个版本,然后您才能为自己创建此扩展。我还提交了一个拉取请求,希望这可以包含在框架本身中。

于 2018-04-20T08:37:04.970 回答