前言?
????????上一篇章總結(jié)了,Spring的創(chuàng)建與使用,通過創(chuàng)建Maven項(xiàng)目配置Spring的環(huán)境依賴,創(chuàng)建Spring框架的項(xiàng)目,然后通過在Resource目錄下創(chuàng)建Spring-config.xml配置文件,添加<bean></bean>標(biāo)簽將我們需要的bean對象注入到容器中,然后通過ApplicationContext獲取Spring上下文,使用getBean()方法獲取bean對象.
? ? ? ? 最后提出了一個(gè)問題就是:當(dāng)我們想注入到容器多個(gè)對象的時(shí)候,我們希望一個(gè)個(gè)的創(chuàng)建標(biāo)簽進(jìn)行創(chuàng)建,因?yàn)檫@樣的操作太繁瑣而且代碼冗余,所以針對上述問題,Spring提供了更加簡單的注入對象的操作,就是通過使用注解來完成上述操作.
目錄
前言?
1. 存儲Bean對象
1.1 配置掃描路徑
1.2 添加類注解
1.2.1 類注解的使用
1.2.2 為什么會有這么多類注解
1.2.3 類注解之間的關(guān)系
1.3 Bean對象的命名規(guī)則
1.4 方法注解@Bean
2.??獲取 Bean 對象(對象裝配)
2.1 屬性注入
2.2 構(gòu)造方法注入
2.3 Setter注入
2.4 三種注入方式的優(yōu)點(diǎn)與缺點(diǎn)
2.5 @Resource 另一種注入關(guān)鍵字
2.6 ?同?類型多個(gè) @Bean 解決
1. 存儲Bean對象
1.1 配置掃描路徑
注意:想要將對象成功的存儲到 Spring 中,我們需要配置?下存儲對象的掃描包路徑,只有被配置的包下的所有類,添加了注解才能被正確的識別并保存到 Spring 中。
在項(xiàng)目的Spring-config.xml進(jìn)行配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:content="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <content:component-scan base-package="com.bit.service"></content:component-scan> </beans>
?
1.2 添加類注解
首先我們之前就接觸過類注解
?上述的@WebServlet就是一個(gè)類注解
在Spring中想要將對象進(jìn)行存儲到Spring中,有兩種注解類型可進(jìn)行實(shí)現(xiàn):
1. 類注解:@Controller @Service @Repository @Component @Configuration
分別對應(yīng):控制器, 服務(wù),倉庫,組件,配置文件
2. 方法注解:@Bean
1.2.1 類注解的使用
這里使用@Controller注解進(jìn)行演示,其他四個(gè)類注解的使用方式都是一樣的.
@Controller // 將對象存儲到 Spring 中
public class UserController {
public void sayHi(String name) {
System.out.println("Hi," + name);
}
}
此時(shí)我們先使?之前讀取對象的?式來讀取上?的 UserController 對象,如下代碼所示:
public class Application {
public static void main(String[] args) {
// 1.得到 spring 上下?
ApplicationContext context =new ClassPathXmlApplicationContext("springconfig.xml");
// 2.得到 bean
UserController userController = context.getBean("userController", UserController.class);
// 3.調(diào)? bean ?法
userController.sayHi("lisi");
}
}
1.2.2 為什么會有這么多類注解
既然功能是?樣的,為什么需要這么多的類注解呢?
這和為什么每個(gè)省/市都有??的?牌號是?樣的??如陜?的?牌號就是:陜X:XXXXXX,北京的?牌號:京X:XXXXXX,?樣。為什么需要怎么多的類注解也是相同的原因,就是讓程序員看到類注解之后,就能直接了解當(dāng)前類的?途.
?
- @Controller:表示的是業(yè)務(wù)邏輯層;
- @Servie:服務(wù)層;
- @Repository:持久層;
- @Configuration:配置層。
?
1.2.3 類注解之間的關(guān)系
查看 @Controller / @Service / @Repository / @Configuration 等注解的源碼發(fā)現(xiàn):
?其實(shí)這些注解里面都有?個(gè)注解 @Component,說明它們本身就是屬于 @Component 的“子類”。
1.3 Bean對象的命名規(guī)則
當(dāng)我們使用applicationContext進(jìn)行獲取上下文,然后通過上下文進(jìn)行獲取容器中的對象的時(shí)候,我們常用的就是傳入兩個(gè)參數(shù):
參數(shù)一: Bean對象類名首字母小寫
參數(shù)二: Bean對象的類對象.
我們平常使用的命名規(guī)則是大駝峰
如果我們?字?和第?個(gè)字?都是?寫時(shí),我們在使用上述的方法進(jìn)行獲取類對象的時(shí)候就不會獲取成功.
?
這個(gè)時(shí)候,我們就要查詢 Spring 關(guān)于 bean 存儲時(shí)?成的命名規(guī)則了, 我們可以在 Idea 中使?搜索關(guān)鍵字“beanName”可以看到以下內(nèi)容:?
?
?它使?的是 JDK Introspector 中的 decapitalize ?法,源碼如下:
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
// 如果第?個(gè)字?和第?個(gè)字?都為?寫的情況,是把 bean 的名字直接存儲了
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&Character.isUpperCase(name.charAt(0))){
return name;
}
// 否則就將?字??寫
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
所以就是遇到首字母和第二個(gè)字母都是大寫的時(shí)候,我們獲取對象的時(shí)候,名字是不變的.
1.4 方法注解@Bean
類注解是添加到某個(gè)類上的,??法注解是放到某個(gè)?法上的,如以下代碼的實(shí)現(xiàn):
@Component
public class Users {
@Bean
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
}
這里需要注意的是,使用方法注解一定要配合方法注解.(因?yàn)橐粋€(gè)項(xiàng)目類已經(jīng)是很多了,每個(gè)類的方法也很多,所以整個(gè)項(xiàng)目的方法就會特別多,所以我們就需要配和類注解進(jìn)行使用)
方法注解,可以將返回的對象的名字進(jìn)行修改,我們在使用方法的時(shí)候,可能會返回許多類型相同的對象,所以我們可以將這些返回的對象進(jìn)行修改名字,以便在以后獲取的時(shí)候更加的方便.代碼如下:
@Component
public class Users {
@Bean(name = {"u1"})
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
// 可以起多個(gè)名字
@Bean(name = {"u1", "us1"})
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
// 省略name的寫法
@Bean({"u1", "us1"})
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
}
獲取方法返回的對象
class App {
public static void main(String[] args) {
// 1.得到 spring 上下?
ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");
// 2.得到某個(gè) bean
User user = context.getBean("u1", User.class);
// 3.調(diào)? bean ?法
System.out.println(user);
}
}
思考:使? @Bean 注解并重命名,嘗試使?原來的類名?字??寫是否能正確獲取到對象?
答案:當(dāng)給@Bean 設(shè)置了name屬性之后,使用原方法名就獲取不到對象了,只能使用別名進(jìn)行獲取.(起了小名,大名就不能用了(挺離譜的,但是要遵循規(guī)則))
2.??獲取 Bean 對象(對象裝配)
獲取 bean 對象也叫做對象裝配,是把對象取出來放到某個(gè)類中,有時(shí)候也叫對象注?。
對象裝配(對象注?)的實(shí)現(xiàn)?法以下 3 種:
- 1. 屬性注入
- 2. 構(gòu)造方法注入
- 3. Setter 注入
接下來,我們分別來看。
2.1 屬性注入
屬性注?是使? @Autowired 實(shí)現(xiàn)的,將 Service 類注?到 Controller 類中。Service 類的實(shí)現(xiàn)代碼如下:
@Service
public class StudentService {
public void sayHi(){
System.out.println("hi");
}
}
?將StudentService 對象注入到Controller中
@Controller
public class StudentController {
// 1.使用屬性注入的方式獲取Bean對象
@Autowired
private StudentService studentService; // 自動將標(biāo)有Service注解studentService對象進(jìn)行注入
public void sayHi(){
// 調(diào)用獲取Bean對象Service的方法進(jìn)行使用
studentService.sayHi();
}
}
測試屬性注入
public static void main4(String[] args) {
// 1.測試屬性注入
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
StudentController studentController = context.getBean("studentController",StudentController.class);
studentController.sayHi();
}
2.2 構(gòu)造方法注入
@Controller
public class StudentController3 {
private StudentService studentService;
@Autowired
// 當(dāng)有一個(gè)構(gòu)造方法的時(shí)候可以將@Autowired省略
public StudentController3(StudentService studentService){
this.studentService = studentService;
}
public void sayHi(){
// 調(diào)用獲取Bean對象Service的方法進(jìn)行使用
studentService.sayHi();
}
}
注意事項(xiàng):如果只有一個(gè)構(gòu)造方法,那么可以將@Autowired進(jìn)行省略.
但是如果類中有多個(gè)構(gòu)造?法,那么需要添加上 @Autowired 來明確指定到底使?哪個(gè)構(gòu)造?法,否則程序會報(bào)錯.
2.3 Setter注入
可以為注入的對象進(jìn)行添加set和get方法,然后給set方法添加@AutoWired注解
@Controller
public class StudentController2 {
private StudentService studentService;
public void sayHi(){
// 調(diào)用獲取Bean對象Service的方法進(jìn)行使用
studentService.sayHi();
}
// 給私有成員變量設(shè)置Setter方法,并且加上@Autowired注解
@Autowired
public void setStudentService(StudentService studentService) {
this.studentService = studentService;
}
}
2.4 三種注入方式的優(yōu)點(diǎn)與缺點(diǎn)
優(yōu)點(diǎn) | 缺點(diǎn) | |
屬性注入 | 使用便捷 | 1.功能性:不能注入一個(gè)final修飾的對象 2.通用性:只適用于IOC容器中 3.設(shè)計(jì)原則: 容易違背單一設(shè)計(jì)原則(使用簡單,犯錯率大) |
構(gòu)造方法注入 | 相對更符合單一設(shè)計(jì)原則 | 1. 不能注入不可變對象 2. 注入的對象隨時(shí)可以被改變 |
setter方法注入 | 使用相對復(fù)雜 | 1.可注入不可變對象 2.注入的對象不會被修改 3.注入的對象可完全被初識化 4.通用性更好 |
2.5 @Resource 另一種注入關(guān)鍵字
在進(jìn)?類注?時(shí),除了可以使用@Autowired 關(guān)鍵字之外,我們還可以使? @Resource 進(jìn)?注?,如下代碼所示:
@Controller
public class StudentController4 {
@Resource(name = "student1")
private Student student;
}
@Autowired 和 @Resource 的區(qū)別
- 出身不同:@Autowired 來自于Spring,而@Resource 來自于JDK 的注解;
- 使用時(shí)設(shè)置的參數(shù)不同:相比于 @Autowired 來說,@Resource ?持更多的參數(shù)設(shè)置,例如name 設(shè)置,根據(jù)名稱獲取 Bean。
- @Autowired 可?于 Setter 注入、構(gòu)造函數(shù)注?和屬性注入,而@Resource 只能用于Setter 注入和屬性注入,不能?于構(gòu)造函數(shù)注入。
- 獲取的Bean對象的順序不同:autowired先根據(jù)名字在根據(jù)類型,Resource先根據(jù)類型再根據(jù)名字進(jìn)行獲取。
2.6 ?同?類型多個(gè) @Bean 解決
@Component
public class Users {
@Bean
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
@Bean
public User user2() {
User user = new User();
user.setId(2);
user.setName("MySQL");
return user;
}
}
@Controller
public class UserController4 {
// 注?
@Resource
private User user;
public User getUser() {
return user;
}
}
?報(bào)錯的原因是,?唯?的 Bean 對象。
解決同?個(gè)類型,多個(gè) bean 的解決?案有以下兩個(gè):
- 使? @Resource(name="user1") 定義。
- 使? @Qualifier 注解定義名稱。
① 使? @Resource(name="XXX")?文章來源:http://www.zghlxwxcb.cn/news/detail-533654.html
@Controller
public class UserController4 {
// 注?
@Resource(name = "user1")
private User user;
public User getUser() {
return user;
}
}
?② 使? @Qualifier文章來源地址http://www.zghlxwxcb.cn/news/detail-533654.html
@Controller
public class UserController4 {
// 注?
@AutoWired
@Qualifier(value = "user2")
private User user;
public User getUser() {
return user;
}
}
到了這里,關(guān)于Spring系列3 -- 更簡單的讀取和存儲對象的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!