现有一个 Student 类,里面有两个属性,分别为 name 和 id;有一个 StuService 类,里面有两个方法,返回值均为类型为 Student 的对象;还有一个 StuController 类,里面有一个 Student 类型的属性,还有一个打印这个属性的方法。代码如下:
Student 类:
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {
private String name;
private Integer id;
}
StuService 类:
@Service
public class StuService {
@Bean
public Student s1() {
return new Student("zhangsan", 12);
}
@Bean
public Student s2() {
return new Student("lisi", 14);
}
}
StuController 类:
@Controller
public class StuController {
//属性注入
@Autowired
public Student student;
public void print() {
System.out.println(student);
}
}
启动类:
@SpringBootApplication
public class SpringBootDemo2025417Application {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(SpringBootDemo2025417Application.class, args);
//获取 StuController 对象
StuController stuController = context.getBean(StuController.class);
stuController.print();
}
}
代码运行结果如下:
Description:
Field student in com.gjm.demo.controller.StuController required a single bean, but 2 were found:
- s1: defined by method 's1' in class path resource [com/gjm/demo/component/StuComponent.class]
- s2: defined by method 's2' in class path resource [com/gjm/demo/component/StuComponent.class]
报错了,错误信息里说只需要一个对象,但却找到了两个。这就是我们在 StuService 中定义的两个方法,这两个方法均返回了 Student 类型的对象,就会造成 Spring 不知道需要使用哪个对象完成属性注入。
有三种解决方法,下面一一说明。
第一种方法,使用 @Qualifier 注解。在 @Autowired 注解上加上 @Qualifier 注解,表明需要注入的是哪个对象,代码如下:
@Controller
public class StuController {
//属性注入
@Qualifier("s1")
@Autowired
public Student student;
public void print() {
System.out.println(student);
}
}
在这里选择了 s1 进行注入,运行结果如下:
结果显示的是 s1 返回的对象,名为 zhangsan。
第二种解决方案为使用 @Resource 注解,代码如下:
@Controller
public class StuController {
@Resource(name = "s2")
private Student student;
public void print() {
System.out.println(student);
}
}
在这里选择 s2 进行注入,运行结果如下:
第三种解决方案就是使用 @Primary 注解,代码如下:
@Service
public class StuService {
@Primary
@Bean
public Student s1() {
return new Student("zhangsan", 12);
}
@Bean
public Student s2() {
return new Student("lisi", 14);
}
}
@Primary 注解用途为将 s1 作为 Student 类的默认注入对象,这样就会优先选择 s1 进行属性注入,运行结果如下:
补充
@Qualifier 在传参的时候也可以指定默认的参数。现有下面代码:
Student 类:
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {
private String name;
private Integer id;
}
StuService 类:
@Service
public class StuService {
@Bean
public String name1() {
return "zhangsan111";
}
@Bean
public String name2() {
return "zhangsan222";
}
@Bean
public Student s1(String name) {
return new Student(name, 12);
}
@Bean
public Student s2() {
return new Student("lisi", 14);
}
}
StuController 类:
@Controller
public class StuController {
@Resource(name = "s1")
private Student student;
public void print() {
System.out.println(student);
}
}
SpringBoot 启动类:
@SpringBootApplication
public class SpringBootDemo2025417Application {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(SpringBootDemo2025417Application.class, args);
//获取 StuController 对象
StuController stuController = context.getBean(StuController.class);
stuController.print();
}
}
代码运行结果如下:
Description:
Parameter 0 of method s1 in com.gjm.demo.service.StuService required a single bean, but 2 were found:
- name1: defined by method 'name1' in class path resource [com/gjm/demo/service/StuService.class]
- name2: defined by method 'name2' in class path resource [com/gjm/demo/service/StuService.class]
报错了,错误信息里说 s1 只需要一个参数,但却找到了两个。这时因为我们向 Spring 容器中注入了两个类型为 String 的对象,当 Spring 为 String 类型的参数赋值时,会在 Spring 容器中查找类型为 String 的对象。现在容器中有两个对象,Spring 不清楚到底需要使用哪一个。这时就需要我们手动指定 Spring 默认使用的参数了,即在参数前使用 @Qualiier 注解,代码如下:
@Bean
public Student s1(@Qualifier("name1") String name) {
return new Student(name, 12);
}
这时 name 参数拿到的就是 name1 返回的结果了,运行结果如下:
@Autowired 与 @Resource 的区别
1、@Autowired 是 Spring 框架提供的注解,@Resource 是 JDK 提供的注解;
2、@Autowired 是按照类型注入的,@Resource 是按照名称注入的,@Resource 支持更多的参数设置。但严谨点说,@Resource 是按照类型 + 名称注入的。