現有一個 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 {@Beanpublic Student s1() {return new Student("zhangsan", 12);}@Beanpublic Student s2() {return new Student("lisi", 14);}
}
StuController 類:
@Controller
public class StuController {//屬性注入@Autowiredpublic 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")@Autowiredpublic 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@Beanpublic Student s1() {return new Student("zhangsan", 12);}@Beanpublic 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 {@Beanpublic String name1() {return "zhangsan111";}@Beanpublic String name2() {return "zhangsan222";}@Beanpublic Student s1(String name) {return new Student(name, 12);}@Beanpublic 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 注解,代碼如下:
@Beanpublic 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 是按照類型 + 名稱注入的。