2

次のように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>

これについての説明はありますか、それともここで何か不足していますか?

4

1 に答える 1

6

<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>

QueueController2 つのインスタンスで終わることになります。これはあなたが望むものではないかもしれません。

IDが原因で発生している動作については、次のとおりです。

アプリケーションコンテキストが を読み取ると、 namecomponent-scanで を登録します。その後、コンテキストは Bean 宣言に移動します。前の定義に equal を指定したため、オーバーライドされます。クラスの Bean 定義は 1 つだけになります。Bean 宣言には特定の引数を持つコンストラクターが必要であり、それがあるため、文句を言うことはなく、Bean が作成されます。BeanComponentDefinitionqueueControlleridQueueController

id別の 、たとえばを指定した場合abcd、アプリケーション コンテキストは 2 つの BeanDefinitions を登録しqueueControllerます。あなたが持っていないデフォルトのコンストラクタが必要です。したがって、例外が発生します。component-scanabcd<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]] 
于 2013-08-26T15:21:52.163 に答える