为什么需要一个无参数的构造函数来运行此简单的Spring配置?

And*_*tin 5 java spring constructor

我试图按照Mkyong上有关Spring 的教程进行学习。我创建了两个简单的类,Customer和Person,如下所示:

客户

public class Customer {

    private Person person;

    public Customer() {
    }

    //Getters and setters for person here

    public String toString() {
        return "Customer [person=" + person +"]";
    }
}
Run Code Online (Sandbox Code Playgroud)

人物

public class Person {

    private String name;
    private String address;
    private int age;

    public Person() {

    }

    public Person(String name, String address, int age) {
        this.name = name;
        this.address = address;
        this.age = age;
    }

    //All getters and setters

    public String toString() {
        return "Person [address=" + address + ", age=" + age + ", name=" + name + "]";
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我使用一个内部bean创建了一个Bean配置文件(这就是我上教程的原因),如下所示:

// Standard bean declarations

    <bean id="CustomerBean" class="com.andrew.SpringInnerBeans.Customer">
        <property name="person">
            <bean class="com.andrew.SpringInnerBeans.Person">
                <property name="name" value="Andrew" />
                <property name="address" value="Address" />
                <property name="age" value="27" />
            </bean>
        </property>
    </bean>
</beans>
Run Code Online (Sandbox Code Playgroud)

最后,我创建了一个MainApp来运行以下代码:

public static void main (String[] args) {

    ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {
            "NewBean.xml"});

    Customer cust = (Customer) context.getBean("CustomerBean");
    System.out.println(cust);

}
Run Code Online (Sandbox Code Playgroud)

现在,据我了解,这是正在发生的事情:

将加载xml文件,并将ID为CustomerBean的bean存储在引用cust(这是一个Customer对象)中。CustomerBean带有一个参数“ person”,创建Person的三个参数的详细信息作为customerBean的内部bean提供。

在MainApp中,将调用参考客户的toString方法,并显示正确的输出。

正如我在示例中专门提供引用一样,为什么需要无参数构造函数来运行此代码?如果删除空的Customer或空的Person构造函数,则代码将失败。当我设置的bean不需要无参数构造函数时,为什么它在运行时失败?

编辑:

代码传递示例:

Customer [person=Person [address=4 Ascot House, age=27, name=Andrew]]
Run Code Online (Sandbox Code Playgroud)

代码示例失败:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CustomerBean' defined in class path resource [NewBean.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.andrew.SpringInnerBeans.Customer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1095)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1040)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
    at com.andrew.SpringInnerBeans.MainApp.main(MainApp.java:10)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.andrew.SpringInnerBeans.Customer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1088)
    ... 13 more
Caused by: java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
    at java.lang.Class.getConstructor0(Unknown Source)
    at java.lang.Class.getDeclaredConstructor(Unknown Source)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80)
    ... 14 more

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CustomerBean' defined in class path resource [NewBean.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.andrew.SpringInnerBeans.Customer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1095)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1040)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
    at com.andrew.SpringInnerBeans.MainApp.main(MainApp.java:10)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.andrew.SpringInnerBeans.Customer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1088)
    ... 13 more
Caused by: java.lang.NoSuchMethodException: com.andrew.SpringInnerBeans.Customer.<init>()
    at java.lang.Class.getConstructor0(Unknown Source)
    at java.lang.Class.getDeclaredConstructor(Unknown Source)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80)
    ... 14 more
Run Code Online (Sandbox Code Playgroud)

Ser*_*sta 5

我们再从 Spring 容器的角度来看一下您所问的问题。

  • 找到了一个 class 的 bean Customer,只有属性:好的,new Customer()使用无参数构造函数创建它并暂时保留它。
  • Person找到一个只有属性的类 bean :好的,将其创建为new Person(),仍然使用无参数构造函数,给它一个任意名称并暂时保留它
  • Person使用 setters填充bean 的属性:好的,它已经准备好了
  • Customer使用 setter 和bean 作为参数来填充bean 的唯一属性Person:好的,它已准备就绪
  • 很好,应用程序上下文现在已完全填充

因此,您从应用程序上下文中获取 bean,并且在您自己的代码中没有new这些 bean,但是 Spring 已经为您构建了它们,并且确实使用了无参数构造函数。

例如,您可以改为:

public class Customer {

    private Person person;

    public Customer(Person person) {
        this.person = person;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

你的 XML 必须是:

<bean id="CustomerBean" class="com.andrew.SpringInnerBeans.Customer">
    <constructor-arg>
        <bean class="com.andrew.SpringInnerBeans.Person">
            <property name="name" value="Andrew" />
            <property name="address" value="Address" />
            <property name="age" value="27" />
        </bean>
    </constructor-arg>
</bean>
Run Code Online (Sandbox Code Playgroud)

这样,Spring 将首先像上面那样构造bean,并使用一个 arg 构造函数Person创建Customerbean 。new Customer(person)