命名类的NoUniqueBeanDefinitionException

时间:2013-03-20 12:59:48

标签: java spring annotations

我正在使用Spring 3.2.2并且想知道是否有一种方法可以按类类型注入bean而不显式给它们一个字符串名称。例如:

@Named
public MyClass{
}

@Named
public MyOtherClass extends MyClass{
}

@Named
public class Foo{
    public void blah(){
       MyClass myClass = context.getBean(MyClass.class);
    }
}

这将产生:

org.springframework.beans.factory.NoUniqueBeanDefinitionException:没有定义[MyClass]类型的限定bean:期望的单个匹配bean但找到2:myClass,myOtherClass

有没有办法说“使用与类名完全匹配的那个”而不使用String名称?

换句话说,我不想这样做:

@Named("MyClass")...
@Named("MyOtherClass")...

MyClass myClass = context.getBean("MyClass");

谢谢!

3 个答案:

答案 0 :(得分:1)

这是§ 5.4.5 of Spring manual在遇到非唯一依赖bean定义时建议的内容:

  • 放弃自动装配以支持显式布线。
  • 通过将autowire-candidate属性设置为false来避免对bean定义进行自动装配,如下一节所述。
  • 通过将其元素的primary属性设置为true,将单个bean定义指定为主要候选者。
  • 如果您使用的是Java 5或更高版本,请使用基于注释的配置实现更精细的控件,如Section 5.9, “Annotation-based container configuration”.
  • 中所述

答案 1 :(得分:1)

例如,您可以执行以下操作:

@Named
public class Foo{
    public void blah(){
       MyClass myClass = getBean(MyClass.class);
    }

    private <T> T getBean(Class<T> type) {
         return context.getBean(Introspector.decapitalize(type.getSimpleName()), type);
    }
}

但使用@Inject@Autowire时,这不起作用。

要在自动装配时强制进行严格的类匹配,您可以使用AutowireCandidateResolver替换BeanFactory上的默认BeanFactoryPostprocessor,但似乎不是@Resource好主意或@Qualify可以解决NUBDE问题。

例如:(未经测试)

public class StrictClassAutowireCandidateResolver implements AutowireCandidateResolver {

    @Override
    public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
        if (!bdHolder.getBeanDefinition().isAutowireCandidate()) {
            return false;
        }

        if (descriptor == null) {
            return true;
        }

        String className = null;

        if (descriptor.getField() != null) {
            className = descriptor.getField().getType().getName();
        }

        else if (descriptor.getMethodParameter() != null) {
            className = descriptor.getMethodParameter().getParameterType().getName();
        }

        Class<?> clazz = null;
        try {
            clazz = Class.forName(className);
        }
        catch (Exception e) {
            return false;
        }

        if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
                // have no chances to be strict, let BeanFactory to find implementations.
                return true;
            }

        return bdHolder.getBeanDefinition().getBeanClassName().equals(className);
    }

    @Override
    public Object getSuggestedValue(DependencyDescriptor descriptor) {
        return null;
    }

}

答案 2 :(得分:0)

尝试在您的类上使用@Component(Service,Repository,Controller),并在注入bean时使用@Autowired。

编辑:我的不好,我没有太好地阅读这个问题。问题是你实际上有2个MyClass实例(因为MyOtherClass从MyClass扩展)。因此除了给出类名之外别无他法,或者你总是会得到NoUniqueBeanDefinitionExceptions。