【问题标题】:Spring dependency injection issueSpring依赖注入问题
【发布时间】:2013-10-11 14:20:37
【问题描述】:

我有一个 bean,我正在尝试使用构造函数注入在 Spring 上下文中进行配置。当我为构造函数参数之一传递子类时,只有当我没有指定“类型”属性时,才会由 Spring 容器实例化 bean。有人知道出了什么问题吗?以下是更多细节。

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

class ConcreteClass extends SomeAbstractBase{
   //
} 

Spring 配置(第一个和第二个不起作用,但使用 type 属性的第三个起作用)- 配置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>

我在初始化时遇到以下异常-

线程“main”中的异常 org.springframework.beans.factory.BeanCreationException:错误 创建在类路径资源中定义的名称为“jedispool”的bean [cache-spring-config.xml]:无法解析匹配的构造函数 (提示:为简单参数指定索引/类型/名称参数 避免类型歧义)

为什么第一个或第二个配置都不起作用?

谢谢

【问题讨论】:

  • 对于上面的示例,您使用的是静态嵌套类吗?

标签: spring


【解决方案1】:

Type 参数只接受完全限定的类型(因为如果不是,spring 无法准确确定包并且类型与您的类不匹配):

所以你需要使用你的类的规范名称作为类型

ConcreteClass => com.your.app.ConcreteClass

一个类不只是一个名字,是一个包+名字(太短了)

【讨论】:

  • 第三个配置也会失败。
  • 嗯,我在我的 webapp 上试过,在类型参数中使用规范的类名。但是在使用 ref 时没有理由指定类型,spring 会自行解析。
  • 我的意思是它会在 concreteclass 的 bean 声明中失败,其中 OP 还指定了一个类名。
  • 是的,我太专注于第二个 bean,我没有看到。你是真的:)
  • 但你几乎是正确的。假设 OP 使用的类是静态嵌套类。
【解决方案2】:

我相信您出现的错误是因为您有 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 属性未正确使用。 ConcreteClass 的完全限定类名是 test.Test$ConcreteClass,而不是我指定的 test.Test.ConcreteClass。这同样适用于MyClassSomeAbstractBase

然而,在class 属性中为concreteclass bean 指定test.Test.ConcreteClass 不会失败,因为在处理bean 声明期间的某个时刻,Spring 会尝试将class 字符串解析为Class 对象使用Class.forName(String)。它将调用ClassUtils.forName(String, ClassLoader) 来执行此操作。最初它会失败,因为没有这样的类test.Test.ConcreteClass。但是,这是在 try-catch 中完成的,ClassNotFoundException 会将 String 类名从 test.Test.ConcreteClass 转换为 test.Test$ConcreteClass 并重试。它将正常工作并为您的 concreteclass bean 创建一个 test.Test$ConcreteClass 类型的 bean。

但是,当它尝试创建您的 myclass bean 时,它不会应用此类逻辑来解析要使用的构造函数,因此无法理解 type 属性值为 test.Test.SomeAbstractBase 时,您实际上是指 @987654352 @,所以它不能说类型不明确。

将您的 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指定完全限定的类名。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-21
    • 2014-12-27
    • 2015-04-22
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-19
    相关资源
    最近更新 更多