现象
使用spring框架,创建对象时应用类型数据采用自动注入的方式,采用byName的语法格式。
xml配置文件:
<bean id="school" class="com.bupt.implement_class.ba01.School">
<property name="name" value="北京大学"/>
<property name="address" value="北京市海淀区"/>
</bean>
<bean id="student1" class="com.bupt.implement_class.ba01.Student" autowire="byName">
<constructor-arg name="name" value="张振仁"/>
<constructor-arg name="age" value="23"/>
</bean>
这里新建的类是Student 引用数据类型为School;
测试类代码:
public class TestStudent {
@Test
public void test01(){
String config="ba01/applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(config);
Student student=(Student) applicationContext.getBean("student1");
System.out.println(student);
}
}
运行会出现如下错误:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'student1' defined in class path resource [ba01/applicationContext.xml]: Unsatisfied dependency expressed through constructor parameter 2: Ambiguous argument values for parameter of type [com.bupt.implement_class.ba01.School] - did you specify the correct bean references as arguments?
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'student1' defined in class path resource [ba01/applicationContext.xml]: Unsatisfied dependency expressed through constructor parameter 2: Ambiguous argument values for parameter of type [com.bupt.implement_class.ba01.School] - did you specify the correct bean references as arguments?
回去仔细检查配置文件和测试类,发现写的没有任何问题。
解决方法
第一步:找到需要测试的类,在类中加上无参数构造方法;
第二部,在applicationContext.xml配置文件中,创建对象时,使用set注入给属性赋值,使用赋值。
修改后的Student的代码:
package com.bupt.implement_class.ba01;
public class Student {
private String name;
private int age;
private School school;
public Student() {
}
public Student(String name, int age, School school) {
this.name = name;
this.age = age;
this.school = school;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setSchool(School school) {
this.school = school;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", school=" + school +
'}';
}
}
修改后的配置文件
<bean id="school" class="com.bupt.implement_class.ba01.School">
<property name="name" value="北京大学"/>
<property name="address" value="北京市海淀区"/>
</bean>
<bean id="student1" class="com.bupt.implement_class.ba01.Student" autowire="byName">
<property name="name" value="张振仁"/>
<property name="age" value="23"/>
</bean>
这样运行就没有问题。
我只测试了使用byName,个人感觉使用byType也一样的。
原因
spring使用bean创建对象时,先找类中的构造方法,如果没有写构造方法,则默认为无参数构造方法;如果写了有参数的构造方法,并且没有写无参数构造方法,则只调用有参数构造方法,而采用构造方法注入的方式给属性赋值,要求在创建对象时把参数传递进去,并且使用时,如果参数没有写完成,代码会爆红出错,就达不到自动注入的目的了。
而我一开始配置文件用的是的方式,但是到了运行阶段就发现依赖不正确,要求无参数构造创建对象,然后set注入赋值,但是类中没有无参数构造方法。
总结
总结:引用类型自动注入应该选用给简单属性赋值,并且在需要测试的类中写明无参数构造方法。