简体   繁体   English

为什么在找不到默认构造函数时Spring引发异常

[英]Why Spring throws exceptions when No default constructor is found

A simple test Shopping Application where i have two classes Clothing and Offers. 一个简单的测试购物应用程序,其中我有两个类服装和优惠。 Now on calling formalshirt bean, it throws the following exception 现在调用formalshirt bean,它引发以下异常

Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'DiwaliOffer' defined in class path resource [spring.xml]: Instantiation of bean failed; 
nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [Offers]: No default constructor found; 
nested exception is java.lang.NoSuchMethodException: Offers.<init>()

Now if i comment the Offers constructor, the app runs successfully. 现在,如果我评论Offer构造函数,则该应用程序将成功运行。 My query is Why does Spring looks for default constructor only when there is another constructor? 我的查询是为什么Spring仅在存在另一个构造函数时才寻找默认构造函数?

Clothing Class 服装类

public class Clothing {
    private int price;
    private List<Offers> offer;

    public void setOffer(List<Offers> offer) {
        this.offer = offer;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

.

Offers Class 优惠等级

public class Offers {
    private int discount;
    private String promocode;

    public Offers(int val1, String val2)
    {
        this.discount=val1;
        this.promocode=val2;
    }

    //public Offers(){} /*Default Constructor added due to Spring Exception as in below */  
    /* Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class No default constructor found */
    /* Caused by: java.lang.NoSuchMethodException: com.test.Shopping.Offers.<init>() */

    public void setDiscount(int discount) {
        this.discount = discount;
    }

    public void setPromocode(String promocode) {
        this.promocode = promocode;
    }
}

Spring.xml Spring.xml

<bean id="formalshirt" class="com.test.Shopping.Clothing">
    <property name="price" value="800"></property>              
    <property name="offer">
        <list>
            <ref bean="DiwaliOffer" />
        </list>
    </property>
</bean>

<bean id="DiwaliOffer" class="com.test.Shopping.Offers">
    <property name="discount" value="10"></property>
    <property name="promocode" value="diwali"></property>
</bean>

You need to change your Spring XML configuration of Offers to: 你需要改变你的Spring XML配置Offers到:

<bean id="DiwaliOffer" class="com.test.Shopping.Offers">
    <constructor-arg value="10"></constructor-arg>
    <constructor-arg value="diwali"></constructor-arg>
</bean>

The way you have configured it, Spring first attempts to call the default constructor and then call the setters. 按照配置方式,Spring首先尝试调用默认构造函数,然后再调用setter。 But of course there is no default constructor, and there fore Spring reports the exception. 但是当然没有默认的构造函数,因此Spring会报告该异常。

Another option if you are using Spring 3+ is to use Java Config, instead of XML config. 如果您使用的是Spring 3+,则另一个选择是使用Java Config,而不是XML config。 You would just have 你只会有

@Configuration
public class AppConfig {

   //add other beans

   @Bean
   public Offers DiwaliOffer() {
      return new Offers(10, diwali);
   }
}

In your case Java Config has the benefit that your configuration would not even compile if you didn't call the constructor, ie. 在您的情况下,Java Config的优势在于,如果您不调用构造函数,即您的配置甚至都不会编译。 it would fail early instead of fail late as with the XML configuration 它会尽早失败,而不是像XML配置那样迟到

Spring is extremely flexible with how it creates beans, but you need to declare how it will be done Spring在创建bean方面非常灵活,但是您需要声明它将如何完成

This is because when you add parametrize constructor , you need to tell spring to intanitate by giving constructor argument... 这是因为当您添加parametrize constructor ,您需要通过给constructor函数提供参数来告诉spring进行初始化。

The concept is straight forward: 这个概念很简单:

in default constriuctor case you will simply create object like new Test() ; 在默认构造函数的情况下,您只需创建像new Test()这样的对象;

where as when you don't have default rather have parameterize constructor you have to create object like new Test1("test") ; 在没有默认值而有参数化构造函数的情况下,必须像new Test1("test")这样创建对象;

Class Test{

}

Class Test1{
      Test1(String a){

}
}

Spring way will be: 春天的方式将是:

<bean id="test1" class="Test1">

<constructor-arg value="Zara"/>
</bean

Please have look at Spring Doc for more details 请查看Spring Doc了解更多详细信息

You need to use constructor-args for your bean properties so that it picks the non-default constructor. 您需要为bean属性使用constructor-args,以便它选择非默认的构造函数。 Otherwise Spring creates the object first, and without any parameters, it must use the zero-arg constructor, then sets properties with setters. 否则,Spring将首先创建对象,并且不带任何参数,它必须使用zero-arg构造函数,然后使用setter设置属性。

To pass in constructor args, change property to constructor-arg like so: 要传递构造函数args,请将属性更改为Constructor-arg,如下所示:

<bean id="DiwaliOffer" class="com.test.Shopping.Offers">

    <constructor-arg index="0" value="10"/>
    <constructor-arg index="1" value="diwali" />

</bean>

If there are any constructor available in the class then java compiler does not provide default constructor. 如果该类中有可用的constructor ,则Java编译器不提供默认的构造函数。

And we can see com.test.Shopping.Clothing can able to create instance and com.test.Shopping.Offers can't. 我们可以看到com.test.Shopping.Clothing可以创建实例,而com.test.Shopping.Offers不能创建实例。

To create the instance you need to pass constructor-arg of discount and promocode . 要创建实例,您需要传递discountpromocode constructor-arg

<bean id="DiwaliOffer" class="com.test.Shopping.Offers">
    <constructor-arg value="10"></property>
    <constructor-arg value="diwali"></property>
</bean>

You can do : 你可以做 :

<bean id="DiwaliOffer" class="com.test.Shopping.Offers" >
    <constructor-arg type="int" value="10" />
    <constructor-arg type="java.lang.String" value="Diwali"/>
</bean>

The constructor-arg element within the bean element is used to set the property value thru constructor injection. bean元素中的builder-arg元素用于通过构造函数注入设置属性值。 Since there is only one constructor in the User bean class, this code will work fine. 由于User bean类中只有一个构造函数,因此此代码可以正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM