You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin实现SpringContext获取Bean报NoUniqueBeanDefinitionException解决方案

问题背景

我们可以通过实现了ApplicationContextAware接口的SpringContext类提供的getBean方法,在非Spring托管类中获取Spring容器管理的Bean,原Java实现代码如下:

@Component
public class SpringContext implements ApplicationContextAware {
    private static ApplicationContext context;

    /**
     * Returns the Spring managed bean instance of the given class type if it exists.
     * Returns null otherwise.
     * @param beanClass
     * @return
     */
    public static <T extends Object> T getBean(Class<T> beanClass) {
        return context.getBean(beanClass);
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        // store ApplicationContext reference to access required beans later on
        SpringContext.context = context;
    }
}

尝试转换为Kotlin版本后代码如下:

@Component
class SpringContext : ApplicationContextAware {
    @Throws(BeansException::class)
    override fun setApplicationContext(context: ApplicationContext) {
        // store ApplicationContext reference to access required beans later on
        SpringContext.Companion.context = context
    }

    companion object {
        private var context: ApplicationContext? = null

        fun <T : Any>getBean(beanClass: KClass<out T>): Any {
            return context!!.getBean(beanClass)
        }
    }
}

调用时抛出如下异常:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'java.lang.Object' available: more than one 'primary' bean found among candidates: [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.annotation.internalPersistenceAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory....]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.determinePrimaryCandidate(DefaultListableBeanFactory.java:1591)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1188)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:420)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:350)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1133)

经排查发现调用时传入的beanClass参数被识别为java.lang.Object类型。


问题产生原因

核心问题出在Kotlin版本getBean方法的返回值声明上:

  • 方法定义的泛型参数T仅用于入参KClass<out T>的约束,没有和返回值绑定,返回值被显式声明为Any类型
  • 当调用该方法时,编译器无法根据返回值目标类型推导泛型参数T的实际类型,会默认将T向上推导为Any,对应传入Spring容器查询的类型就是java.lang.Object
  • Spring容器内所有Bean都是Object的子类,自然会匹配到大量候选Bean,最终抛出无唯一Bean的异常

解决方案

修正getBean方法的返回值声明,将返回类型绑定到泛型参数T即可。如果需要适配Kotlin的使用习惯,还可以额外增加带reified泛型的重载方法,调用时不需要手动传入KClass参数。

修正后的完整Kotlin代码如下:

@Component
class SpringContext : ApplicationContextAware {
    @Throws(BeansException::class)
    override fun setApplicationContext(context: ApplicationContext) {
        // 存储ApplicationContext引用,后续用于获取Bean
        SpringContext.context = context
    }

    companion object {
        private var context: ApplicationContext? = null

        // 修正返回值为泛型T,而非Any
        fun <T : Any> getBean(beanClass: KClass<out T>): T {
            return context!!.getBean(beanClass)
        }
        
        // 可选:新增reified泛型重载,调用更便捷
        inline fun <reified T : Any> getBean(): T {
            return context!!.getBean(T::class)
        }
    }
}

修正后的调用示例:

  • 兼容原有传参方式:val userService = SpringContext.getBean(UserService::class)
  • Kotlin专属简化调用:val userService = SpringContext.getBean<UserService>()

内容的提问来源于stack exchange,提问作者Sarthak Mittal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 17:15:02