对于没有“id”属性的bean,Spring bean创建失败

时间:2013-08-26 15:18:24

标签: java spring spring-mvc

我有一个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;
    }
}

我的context-configuration文件中的相应条目如下(其中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>

对此的任何解释或我在这里遗漏了什么?

1 个答案:

答案 0 :(得分:5)

我假设你的配置中有<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的{​​{1}}。然后上下文继续进行bean声明。因为您已指定queueController等于之前的定义,所以它将覆盖它。对于id类,最终只会有一个bean定义。由于bean声明需要一个具有特定参数的构造函数,并且你拥有它,它不会抱怨并将创建bean。

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

更详细

如果您使用的是<bean>,请查看queueController方法的以下致电

ClassPathXmlApplicationContext

ClassPathBeanDefinitionScanner#doScan(String...)String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); 的一个实例。它最终调用

beanNameGenerator

调用

AnnotationBeanNameGenerator

返回默认名称// Fallback: generate a unique default bean name. return buildDefaultBeanName(definition, registry); 。那是你String shortClassName = ClassUtils.getShortName(definition.getBeanClassName()); return Introspector.decapitalize(shortClassName); 覆盖的那个。

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

queueController