我将假设您<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
with name queueController
。然后上下文转到您的 bean 声明。因为您已经指定了id
等于先前定义的值,所以它将覆盖它。您最终将只为您的QueueController
类定义一个 bean。由于 bean 声明需要具有特定参数的构造函数并且您拥有它,因此它不会抱怨并会创建 bean。
如果你指定了一个不同的id
,比如说abcd
,你的应用程序上下文将注册两个 BeanDefinitions:一个带有来自 的名称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
。那就是你要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]]