0

コンストラクター注入を使用して、Spring コンテキストで構成しようとしている Bean があります。コンストラクター引数の 1 つにサブクラスを渡すと、"type" 属性を指定しない場合にのみ、Spring コンテナーによって Bean がインスタンス化されます。誰が何が悪いのか分かりますか?以下は、より具体的なものです。

class MyClass{
   public MyClass(SomeAbstractBase absObject){
      //do stuff
   }
}

class ConcreteClass extends SomeAbstractBase{
   //
} 

Spring 構成 (1 番目と 2 番目は機能しませんが、type 属性を使用する 3 番目は機能します)- 構成 I-

<bean id="concreteclass" 
         class="ConcreteClass"/>
<bean id="myclass" 
        class="MyClass">
        <constructor-arg type="ConcreteClass" ref="concreteclass"/>
</bean>

コンフィグⅡ-

<bean id="concreteclass" 
         class="ConcreteClass"/>
<bean id="myclass" 
        class="MyClass">
        <constructor-arg type="SomeAbstractBase" ref="concreteclass"/>
</bean>

コンフィグⅢ-

 <bean id="concreteclass" 
             class="ConcreteClass"/>
    <bean id="myclass" 
            class="MyClass">
            <constructor-arg ref="concreteclass"/>
    </bean>

初期化時に次の例外が発生します-

スレッド「メイン」での例外 org.springframework.beans.factory.BeanCreationException: クラスパス リソース [cache-spring-config.xml] で定義された名前 'jedispool' を持つ Bean の作成中にエラーが発生しました: 一致するコンストラクターを解決できませんでした (ヒント: index/ を指定してください)タイプのあいまいさを避けるための単純なパラメーターのタイプ/名前引数)

最初の構成も 2 番目の構成も機能しないのはなぜですか?

ありがとうございました

4

2 に答える 2

0

staticネストされたクラスがあったために表示されたエラーだと思います。SSCCEはこちら

package test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
    public static void main(String[] args) throws Exception {
        System.out.println(MyClass.class.getName());
        System.out.println(ConcreteClass.class.getName());
        System.out.println(SomeAbstractBase.class.getName());
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");  
    }
    static class MyClass {
        public MyClass(SomeAbstractBase absObject) {
        }
    }
    static class ConcreteClass extends SomeAbstractBase {
        //
    }
    static abstract class SomeAbstractBase {
    }
}

spring.xml入りで

<bean id="concreteclass" class="test.Test.ConcreteClass" />
<bean id="myclass" class="test.Test.MyClass">
    <constructor-arg  type="test.Test.SomeAbstractBase" ref="concreteclass" />
</bean>

上記は で失敗しますUnsatisfiedDependencyException。この特定の例では、class属性が正しく使用されていません。の完全修飾クラス名ConcreteClasstest.Test$ConcreteClasstest.Test.ConcreteClass私が指定したものではありません。MyClassとについても同様SomeAbstractBaseです。

ただし、Bean 宣言の処理中のある時点で、Spring は を使用してString をオブジェクトに解決しようとするため、Bean の属性で指定test.Test.ConcreteClassしても失敗しません。これを行うために呼び出されます。そのようなクラスがないため、最初は失敗します。ただし、これは で行われ、クラス名が からに変換され、再試行されます。それは機能し、Bean のタイプの Bean を正しく作成します。classconcreteclassclassClassClass.forName(String)ClassUtils.forName(String, ClassLoader)test.Test.ConcreteClasstry-catchClassNotFoundExceptionStringtest.Test.ConcreteClasstest.Test$ConcreteClasstest.Test$ConcreteClassconcreteclass

ただし、Beanを作成しようとすると、myclassどのコンストラクターを使用するかを解決するためのそのようなロジックが適用されないため、type属性値が であることを理解できずtest.Test.SomeAbstractBase、実際には を意味するtest.Test$SomeAbstractBaseため、型があいまいであると言って失敗します。

Bean 宣言を正しいタイプに変更します

<bean id="concreteclass" class="test.Test$ConcreteClass" />
<bean id="myclass" class="test.Test$MyClass">
    <constructor-arg  type="test.Test$SomeAbstractBase" ref="concreteclass" />
</bean>

そしてそれはうまくいくでしょう。

kakawait's answerを見てください。インスタンス化しようとしている Bean の完全修飾クラス名を指定する必要があります。

于 2013-10-11T16:20:01.203 に答える
0

タイプ引数は完全修飾タイプのみを受け入れます(そうでない場合、Spring はパッケージを正確に判断できず、タイプがクラスと一致しないため)。

したがって、クラスの正規名を使用してタイプにする必要があります

ConcreteClass => com.your.app.ConcreteClass

クラスは単なる名前ではなく、パッケージ + 名前です (短すぎます)

于 2013-10-11T14:29:57.803 に答える