我正试图在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 +"]";
}
}
人:
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 + "]";
}
}
然后我创建了一个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>
最后,我创建了一个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);
}
现在,根据我的理解,这就是正在发生的事情:
加载xml文件,ID为CustomerBean的bean存储在引用cust(它是Customer对象)中。 CustomerBean接受一个参数&#34; person&#34;,并且创建Person的三个参数的详细信息作为customerBean的内部bean提供。
在MainApp中,调用引用cust的toString方法并显示正确的输出。
由于我在我的示例中专门提供了引用,为什么运行此代码需要无参数构造函数?如果我删除空Customer或空Person构造函数,代码将失败。为什么它在运行时失败,当我设置的bean不需要无参数构造函数时?
编辑:
代码传递示例:
Customer [person=Person [address=4 Ascot House, age=27, name=Andrew]]
代码失败的示例:
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
答案 0 :(得分:2)
因为它使用字段注入而不是您的Person(String name,String address,int age)构造函数。请尝试类似:
...
<property name="person">
<bean class="com.andrew.SpringInnerBeans.Person">
<constructor-arg index="0" value="Andrew"/>
<constructor-arg index="1" value="Address"/>
<constructor-arg index="2" value="27"/>
</bean>
</property>
...
代替。这是Person类的解决方案,对于客户 - 我不知道; )
答案 1 :(得分:2)
再看一下你从Spring容器的角度提出的要求。
Customer
的bean,只有属性:ok使用no-arg构造函数创建它为new Customer()
并暂时保留它。Person
类的bean,只有属性:ok创建它为new Person()
,仍然使用no-arg构造函数,给它一个任意名称并暂时保留它Person
bean及其属性:ok it ready Customer
bean作为参数填充Person
bean的唯一属性:ok it ready 因此,您从应用程序上下文中获取bean并且在您自己的代码中没有new
,但是Spring已经为您构建了它们,并且确实使用了无参数构造函数。
你可以改为举例:
public class Customer {
private Person person;
public Customer(Person person) {
this.person = person;
}
...
}
你的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>
这样,Spring将首先构建Person
bean,并使用一个arg构造函数创建Customer
bean作为new Customer(person)
。
答案 2 :(得分:1)
这是XML文件设置的问题。您没有提供构造函数参数,而是告诉Spring实例化具有某些属性的新对象。
看到这个堆栈溢出帖子: Does Spring require all beans to have a default constructor?
您必须提供构造函数参数,以便通知Spring您希望将构造函数与参数一起使用。
即:
<bean id="CustomerBean" class="com.andrew.SpringInnerBeans.Customer">
<property name="person">
<bean class="com.andrew.SpringInnerBeans.Person">
<constructor-arg index="0" value="Andrew"/>
<constructor-arg index="1" value="Address"/>
<constructor-arg index="2" value="27"/>
</bean>
</property>
</bean>
这将告诉Spring你想要使用提供的构造函数来接受参数而不是no-arg构造函数。从技术上讲,您根本不需要提供默认构造函数。
答案 3 :(得分:1)
为什么在运行时,当我设置的bean不需要无参数构造函数时,它会失败?
您设置的bean 需要一个无参数构造函数。我不是Spring专家(事实上一直困在他们身上)但是你要求Spring做的事情:
freakman's answer展示了如何使用构造函数参数创建Person对象,我想你也可以类似地创建客户对象。那么你不应该需要无法治疗的人。