繁体   English   中英

没有“ id”属性的bean的Spring Bean创建失败

[英]Spring bean creation is failing for beans without an “id” attribute

我有一个Spring控制器定义,如下所示:

@Controller
@RequestMapping("/queue")
public class QueueController {

    QueuesService queueService;

    public QueueController(QueuesService queueService) {
        if (queueService == null) {
            throw new IllegalArgumentException("QueueService cannot be null");
        }
        this.queueService = queueService;
    }
}

我的上下文配置文件中的相应条目如下(其中bean定义没有任何“ id”属性):

 <bean class="com.xy.web.controllers.QueueController">
<constructor-arg ref="queueServiceImpl"></constructor-arg>
</bean>

现在,在应用程序启动期间,Spring抛出以下异常:

Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.xy.web.controllers.QueueController]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.xy.web.controllers.QueueController.<init>()

但是,当我将“ id”属性添加到“ bean定义”(如下所示)时,将正确创建它。

<bean id="queueController" class="com.xy.web.controllers.QueueController">
    <constructor-arg ref="queueServiceImpl"></constructor-arg>
</bean>

有什么解释吗?还是我在这里遗漏了什么?

我将假设您的配置中有<content:component-scan ...> 这将尝试实例化任何@Component注释的类。 @Controller是一个@Component因此Spring将尝试使用类默认的空构造函数实例化QueueController 在您的情况下,这样的构造函数不存在。 因此,它将引发您所看到的异常。

您需要添加一个空的构造函数

public QueueController() {}

无论您的bean声明如何,都会发生这种情况

<bean class="com.xy.web.controllers.QueueController">
    <constructor-arg ref="queueServiceImpl"></constructor-arg>
</bean>

您将最终得到两个QueueController实例。 这可能不是您想要的。

至于由于id而导致的行为:

当应用程序上下文读取component-scan它将登记一个BeanComponentDefinition与名称queueController 然后上下文将移至您的bean声明。 由于您指定的id等于先前的定义,因此它将覆盖它。 最后,您将只为QueueController类定义一个bean。 由于bean声明需要一个带有特定参数的构造函数,而您拥有该参数,因此它不会抱怨,并且会创建bean。

如果您指定了另一个id ,例如abcd ,则您的应用程序上下文将注册两个BeanDefinition:一个来自component-scan ,名称为queueController (遵循默认名称生成策略),另一个来自<bean>声明,名称为abcd queueController需要您没有的默认构造函数。 因此,您将获得例外。

更详细

如果您使用的是ClassPathXmlApplicationContext ,请查看ClassPathBeanDefinitionScanner#doScan(String...)方法的以下调用

String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

beanNameGeneratorAnnotationBeanNameGenerator的实例。 最终它呼唤

// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);

哪个电话

String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
return Introspector.decapitalize(shortClassName);

返回默认名称queueController 那就是您的id覆盖的那个。

您实际上可以在日志中看到:

Mon Aug 26 12:12:15 EDT 2013 [main] INFO  o.s.b.f.s.DefaultListableBeanFactory - Overriding bean definition for bean 'queueController': replacing [Generic bean: class [org.test.QueueController]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\Users\sotirios.delimanolis\git\content-store\target\test-classes\org\test\QueueController.class]] with [Generic bean: class [org.test.QueueController]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [app.xml]] 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM