Java 为什么在找不到默认构造函数时 Spring 会抛出异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24300117/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 11:21:59  来源:igfitidea点击:

Why Spring throws exceptions when No default constructor is found

javaspring

提问by aj_blk

A simple test Shopping Application where i have two classes Clothing and Offers. Now on calling formalshirtbean, it throws the following exception

一个简单的测试购物应用程序,其中我有两个类 Clothing 和 Offers。现在在调用formalshirtbean时,它会抛出以下异常

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. My query is Why does Spring looks for default constructor only when there is another constructor?

现在,如果我评论 Offers 构造函数,应用程序将成功运行。我的查询是为什么 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

弹簧文件

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

采纳答案by geoand

You need to change your Spring XML configuration of Offersto:

您需要将 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. But of course there is no default constructor, and there fore Spring reports the exception.

根据您配置它的方式,Spring 首先尝试调用默认构造函数,然后调用 setter。但是当然没有默认构造函数,因此Spring会报告异常。

Another option if you are using Spring 3+ is to use Java Config, instead of XML config. You would just have

如果您使用的是 Spring 3+,另一个选择是使用 Java Config,而不是 XML config。你只要

@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. it would fail early instead of fail late as with the XML configuration

在您的情况下,Java Config 的好处是,如果您不调用构造函数,您的配置甚至不会编译。它会提前失败而不是像 XML 配置一样失败

Spring is extremely flexible with how it creates beans, but you need to declare how it will be done

Spring 在创建 bean 的方式上非常灵活,但是您需要声明它将如何完成

回答by Subhrajyoti Majumder

If there are any constructoravailable in the class then java compiler does not provide default constructor.

如果类中有任何constructor可用,则 java 编译器不提供默认构造函数。

And we can see com.test.Shopping.Clothingcan able to create instance and com.test.Shopping.Offerscan't.

我们可以看到com.test.Shopping.Clothing可以创建实例而com.test.Shopping.Offers不能。

To create the instance you need to pass constructor-argof discountand promocode.

要创建你需要通过实例constructor-argdiscountpromocode

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

回答by Jayaram

This is because when you add parametrize constructor, you need to tell springto intanitate by giving constructorargument...

这是因为当你添加时parametrize constructor,你需要spring通过给出constructor参数来告诉intanitate ......

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:

Spring方式将是:

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

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

Please have look at Spring Docfor more details

请查看Spring Doc以获取更多详细信息

回答by codenheim

You need to use constructor-args for your bean properties so that it picks the non-default constructor. Otherwise Spring creates the object first, and without any parameters, it must use the zero-arg constructor, then sets properties with setters.

您需要为 bean 属性使用构造函数参数,以便它选择非默认构造函数。否则 Spring 首先创建对象,并且没有任何参数,它必须使用零参数构造函数,然后使用 setter 设置属性。

To pass in constructor args, change property to constructor-arg like so:

要传入构造函数参数,请将属性更改为构造函数参数,如下所示:

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

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

</bean>

回答by user3145373 ツ

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. Since there is only one constructor in the User bean class, this code will work fine.

bean 元素中的 constructor-arg 元素用于通过构造函数注入设置属性值。由于 User bean 类中只有一个构造函数,因此这段代码可以正常工作。