Spring?使用注解存儲(chǔ)和讀取?Bean對(duì)象操作方法
前言
前面的文章詳細(xì)的介紹了 Spring 對(duì)象的創(chuàng)建,以及對(duì) Bean 對(duì)象的存取操作,但是通過配置文件注冊(cè) Bean 對(duì)象以及使用 ApplicationContext
或 BeanFactory
的方式獲取 Bean 對(duì)象的操作就顯得格外的復(fù)雜。因此,本文主要就是詳細(xì)介紹了一種更加簡(jiǎn)單的方式來實(shí)現(xiàn)對(duì) Bean 對(duì)象更加簡(jiǎn)單的儲(chǔ)存和讀取操作。
在 Spring 中,要想更加簡(jiǎn)單的實(shí)現(xiàn)對(duì) Bean 對(duì)象的儲(chǔ)存和使用,其核心就是使用 注解
,本文主要就是演示如何使用注解實(shí)現(xiàn)對(duì) Bean 對(duì)象的存取操作。
一、使用注解儲(chǔ)存 Bean 對(duì)象
在之前儲(chǔ)存 Bean 對(duì)象的時(shí)候,還需在 spring-congig
文件中添加一行 <bean>
內(nèi)容才行,而且,每需要新增一個(gè) Bean 對(duì)象到 Spring 容器中就需要新增一行,這樣的操作就顯得非常麻煩了。
而現(xiàn)在只需要使用一個(gè) 注解
就能代替這一行 <bean>
內(nèi)容,此時(shí)就變得非常方便。想要通過注解的方式將對(duì)象儲(chǔ)存到 Spring 容器中,主要有兩種注解類型可以實(shí)現(xiàn):
1.使用類注解(五大類注解):
@Controller
(控制儲(chǔ)存):驗(yàn)證用戶請(qǐng)求的數(shù)據(jù)合法性,相當(dāng)于安保系統(tǒng);@Service
(服務(wù)儲(chǔ)存):用于編排和調(diào)度具體的執(zhí)行方法;@Repository
(倉(cāng)庫(kù)儲(chǔ)存):持久層,與數(shù)據(jù)庫(kù)進(jìn)行交換;@Component
(組件儲(chǔ)存):相當(dāng)于工具類;@Configuration
(配置儲(chǔ)存):項(xiàng)目中的一些配置。
2.使用方法注解:
@Bean
:作用在方法上,需要配合上述的類注解使用。
但在此之前還需要配置一下 掃描路徑
。
1.1 配置掃描路徑
在 spring-config.xml
文件中添加如下一行記錄:
其含義是,指定一個(gè) base package
,即所有需要添加到 Spring 容器中的 Bean 對(duì)象都在 base package
所指定包或者其子包下。這里我知道的包是 com.spring.demo
,那么就意味著,如果不是此包下的 Bean 對(duì)象,即使加上了注解,也不會(huì)被添加到 Spring 容器中。
1.2 類注解儲(chǔ)存 Bean 對(duì)象
1.2.1 @Controller(控制器存儲(chǔ))
使用 @Controller
注解儲(chǔ)存 Bean 對(duì)象:
@Controller public class StudentController1 { public void sayHi(){ System.out.println("do studentController1 sayHi()."); } }
使用 ApplicationContext
的方式獲取 Bean 對(duì)象:
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); StudentController1 studentController1 = context.getBean("studentController1", StudentController1.class); studentController1.sayHi(); }
關(guān)于 Bean 對(duì)象的命名規(guī)則可見后文。
1.2.2 @Service(服務(wù)儲(chǔ)存)
使用 @Service
注解儲(chǔ)存 Bean 對(duì)象:
@Service public class StudentController2 { public void sayHi(){ System.out.println("do studentController2 sayHi()."); } }
獲取 Bean 對(duì)象:
StudentController2 studentController2 = context.getBean("studentController2", StudentController2.class);
1.2.3 @Repository(倉(cāng)庫(kù)存儲(chǔ))
使用 @Repository
注解儲(chǔ)存 Bean 對(duì)象:
@Repository public class StudentController3 { public void sayHi(){ System.out.println("do studentController3 sayHi()."); } }
獲取 Bean 對(duì)象:
StudentController3 studentController3 = context.getBean("studentController3", StudentController3.class);
1.2.4 @Component(組件儲(chǔ)存)
使用 @Component
注解儲(chǔ)存 Bean 對(duì)象:
@Component public class StudentController4 { public void sayHi(){ System.out.println("do studentController4 sayHi()."); } }
獲取 Bean 對(duì)象:
StudentController4 studentController4 = context.getBean("studentController4", StudentController4.class);
1.2.5 @Configuration(配置儲(chǔ)存)
使用 @Configuration
注解儲(chǔ)存 Bean 對(duì)象:
@Configuration public class StudentController5 { public void sayHi(){ System.out.println("do studentController5 sayHi()."); } }
獲取 Bean 對(duì)象:
StudentController5 studentController5 = context.getBean("studentController5", StudentController5.class);
1.2.6 Bean 命名規(guī)則
通過上述代碼可以發(fā)現(xiàn),在創(chuàng)建 Bean 對(duì)象的時(shí)候,都是使用的標(biāo)準(zhǔn) “大駝峰” 的命名方式,而讀取的時(shí)候 Bean 的名稱則是其類名稱的首字母小寫,即小駝峰。
但是,此時(shí)創(chuàng)建一個(gè) SController
類,并使用注解將其添加到 Spring 容器中,那么此時(shí)它的 Bean 對(duì)象的名稱是什么呢?根據(jù)上面代碼的規(guī)律,難道還是 SController
嗎?
SController sController = context.getBean("sController", SController.class);
當(dāng)運(yùn)行程序的時(shí)候,發(fā)現(xiàn)報(bào)錯(cuò)了:
其意思是不存在名稱為 sController
這樣 Bean 對(duì)象。此時(shí)如果將其改成 SController
,會(huì)是正確的嗎?
此時(shí)發(fā)現(xiàn)便能正常運(yùn)行了。
關(guān)于 Bean 的名稱生成的源碼:
查找 beanname,選擇 AnnotationBeanNameGenerator
類
繼續(xù)查找
繼續(xù)查找
4. 找到了源碼,即 Introspector
類下的 decapitalize
方法
該方法通過檢查字符串的首字母是否為大寫,并且第二個(gè)字符也是大寫的情況下,直接返回原字符串,不做小寫化處理。這樣做是為了避免一些特殊情況下,例如縮寫或首字母縮寫詞,不被誤處理。
1.3 五大類注解的作用
在Spring框架中,五大類常用的注解,分別是:@Component、@Controller、@Service、@Repository和@Configuration。
@Component
: 通用的組件注解,表示類是一個(gè)Spring管理的組件(Bean)。@Controller
: 用于標(biāo)識(shí)控制器類,通常用于Spring MVC中,處理HTTP請(qǐng)求和視圖渲染。@Service
: 用于標(biāo)識(shí)服務(wù)類,表示該類提供一些業(yè)務(wù)邏輯處理。@Repository
: 用于標(biāo)識(shí)倉(cāng)庫(kù)類,表示該類用于數(shù)據(jù)訪問,通常與數(shù)據(jù)庫(kù)交互。@Configuration
: 用于標(biāo)識(shí)配置類,表示該類包含Spring配置信息,通常與@Bean
一起使用,用于定義 Bean。
1.3.1 為什么有這么多的注解
通過上面代碼的演示,發(fā)現(xiàn)這些注解的功能都是一樣的,既然都是一樣的為什么還需要有這么多不同的注解呢?
Spring 之所以提供這么多的注解,是為了更好的組織和管理應(yīng)用程序的組件和依賴關(guān)系。因?yàn)槊總€(gè)注解都有自己特定的用途,讓開發(fā)人員在應(yīng)用程序中能夠更方便地標(biāo)識(shí)和區(qū)分不同類型的類。同時(shí)也提現(xiàn)了程序的工程分層:
- 其中
@Controller
表示的是控制層,負(fù)責(zé)與用戶進(jìn)行交互,以及驗(yàn)證用戶提交數(shù)據(jù)的合法性; @Service
表示的是服務(wù)層,用于編排和調(diào)度具體的執(zhí)行方法,相當(dāng)于車站中的服務(wù)臺(tái);@Repository
表示的是持久層,負(fù)責(zé)將數(shù)據(jù)持久化儲(chǔ)存,通常需要與數(shù)據(jù)庫(kù)進(jìn)行交互。
以上三個(gè)層次實(shí)現(xiàn)了程序的工程分層,同時(shí)也是 Java EE 標(biāo)準(zhǔn)分層的最核心分層。
1.3.2 類注解之間的關(guān)系
查看 @Controller / @Service / @Repository / @Configuration
等注解的源碼發(fā)現(xiàn):
它們都是 @Component
子類注解,這意味著,被標(biāo)注為 @Controller / @Service / @Repository / @Configuration
的類也被視為 @Component
。
- 另外,
@Configuration
注解是一個(gè)特殊的注解,它表明該類是 Spring 的配置類,用于定義 Bean 和配置應(yīng)用程序的其他元素。配置類中的@Bean
注解用于定義 Bean。
1.4 方法注解儲(chǔ)存 Bean 對(duì)象
首先創(chuàng)建一個(gè) User 實(shí)體類:
package com.spring.demo.entity; /** * 普通的用戶實(shí)體類 */ public class User { private Integer uid; private String username; private String password; private Integer age; public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "uid=" + uid + ", username='" + username + '\'' + ", password='" + password + '\'' + ", age=" + age + '}'; } }
1.4.1 @Bean 注解的使用
創(chuàng)建一個(gè)組件類 UserBeans
,并使用方法注解 @Bean
將 User 類添加到 Spring 容器中:
@Controller public class UserBeans { @Bean public User getUser(){ User user = new User(); user.setUid(1); user.setUsername("王五"); user.setPassword("123456"); user.setAge(18); return user; } }
注意,使用方法注解 @Bean
的時(shí)候需要搭配五大類注解才能生效。
獲取 Bean 對(duì)象:
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); User user = context.getBean("getUser", User.class); System.out.println(user); }
注意,當(dāng)使用方法注解 @Bean
的時(shí)候,Bean 對(duì)象的默認(rèn)名稱就是其 添加到 Spring 容器中的方法名。
1.4.2 Bean 對(duì)象重命名
如果直接使用方法名作為 Bean 對(duì)象的名稱,例如 getUser
就顯得非常的不合理,因此往往需要對(duì) Bean 進(jìn)行改名操作。但查看 @Bean
源碼的時(shí)候可以發(fā)現(xiàn),其中的 name
或 value
屬性是一個(gè)數(shù)組,那么就意味著可以一個(gè) Bean 對(duì)象取多個(gè)名稱。
例如:
此時(shí),可通過這兩個(gè)名稱,獲取該 Bean 對(duì)象,發(fā)現(xiàn)它們是同一個(gè) Bean:
另外需要注意的是,如果對(duì) Bean 進(jìn)行了重命名,則原來默認(rèn)的方法名就失效了。
二、使用注解獲取 Bean 對(duì)象
2.1 Bean 對(duì)象通過注解獲取的方法
獲取 Bean 對(duì)象也叫做 對(duì)象裝配
,即把對(duì)象取出來放到某個(gè)類當(dāng)中,同時(shí)也叫做 對(duì)象注入
。
對(duì)象注入的實(shí)現(xiàn)方式有以下三種:
- 屬性注入:屬性注入是通過在屬性上使用注解實(shí)現(xiàn)的。常見的注解有
@Autowired
和@Resource
。屬性注入是在 Bean 對(duì)象的屬性上直接進(jìn)行注入,不需要提供setter
方法。 Setter
注入:Setter
注入是通過在 Bean 對(duì)象的setter
方法上使用注解實(shí)現(xiàn)的。這種注入方式是在調(diào)用 Bean 的setter
方法時(shí),將依賴對(duì)象作為參數(shù)傳入。- 構(gòu)造方法注入:構(gòu)造方法注入是通過在 Bean 對(duì)象的構(gòu)造方法上使用注解實(shí)現(xiàn)的。這種注入方式是在創(chuàng)建 Bean 對(duì)象的時(shí)候,通過構(gòu)造方法參數(shù)傳入依賴對(duì)象。
2.2 三種注入方法的使用
下?按照實(shí)際開發(fā)中的模式,將 Service 類注入到 Controller 類中,然后通過 main
方法獲取 Controller 中的 Bean 對(duì)象。首先創(chuàng)建一個(gè) UserService
類和 UserController
類:
@Service public class UserService { public void sayHi(){ System.out.println("hi, userService."); } }
2.2.1 屬性注入
@Controller public class UserController { // 1. 屬性注入 @Autowired private UserService userService; public void sayHi(){ System.out.println("do userController sayHi()."); userService.sayHi(); } }
2.2.2 Setter 注入
@Controller public class UserController { // 2. setter 注入 private UserService userService; @Autowired public void setUserService(UserService userService) { this.userService = userService; } public void sayHi(){ System.out.println("do userController sayHi()."); userService.sayHi(); } }
2.2.3 構(gòu)造方法注入
@Controller public class UserController { // 3. 構(gòu)造方法注入 private UserService userService; // @Autowired public UserController(UserService userService) { this.userService = userService; } public void sayHi(){ System.out.println("do userController sayHi()."); userService.sayHi(); } }
注意,如果此時(shí)只有一個(gè)構(gòu)造方法,則 @Autowired
可以省略。
2.3 三種注入方法的優(yōu)缺點(diǎn)
屬性注入
- 優(yōu)點(diǎn):簡(jiǎn)潔,代碼量少,適合對(duì)屬性直接注入的情況;
- 缺點(diǎn):
- 對(duì)于必須注入的屬性,如果沒有找到匹配的Bean,會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤;
- 兼容不好,只能用于 IoC 容器;
- 沒辦法實(shí)現(xiàn)
finally
修飾的變量實(shí)現(xiàn)注入; - 過于簡(jiǎn)單,容易違背單一設(shè)計(jì)原則。
Setter注入:
- 優(yōu)點(diǎn):符合單一設(shè)計(jì)原則,每個(gè)方法只能傳遞一個(gè)對(duì)象。
- 缺點(diǎn):
- 沒辦法實(shí)現(xiàn)
finally
修飾的變量實(shí)現(xiàn)注入; - 使用 Setter 注入的對(duì)象可能會(huì)被修改。
- 沒辦法實(shí)現(xiàn)
構(gòu)造方法注入:
- 優(yōu)點(diǎn):
- 可以實(shí)現(xiàn)
finally
修飾的變量實(shí)現(xiàn)注入; - 注入的對(duì)象不會(huì)被改變,即構(gòu)造方法只能執(zhí)行一次;
- 構(gòu)造方法注入可以保證注入對(duì)象完全被初始化。
- 可以實(shí)現(xiàn)
- 缺點(diǎn):構(gòu)造方法參數(shù)較多時(shí),代碼顯得冗長(zhǎng)。
2.4 @Resource 注入
在進(jìn)行類注入時(shí),除了可以使用 @Autowired
關(guān)鍵字之外,我們還可以使用 @Resource
進(jìn)行注入,如下代碼所示:
屬性注入:
public class UserController { // 1. 屬性注入 @Resource private UserService userService; public void sayHi(){ System.out.println("do userController sayHi()."); userService.sayHi(); } }
Setter注入:
@Controller public class UserController { // 2. setter 注入 private UserService userService; @Resource public void setUserService(UserService userService) { this.userService = userService; } public void sayHi(){ System.out.println("do userController sayHi()."); userService.sayHi(); } }
遺憾的是, @Resource
不支持構(gòu)造方法注入:
2.5 @Autowired 和 @ Resource的區(qū)別
@Autowired
是 Spring 框架提供的注解,而@Resource
是JSR-250規(guī)范提供的注解,但是 Spring 也對(duì)其進(jìn)行了支持。@Autowired
默認(rèn)按照類型裝配 Bean,如果多個(gè)類型匹配,可以配合@Qualifier
注解指定具體的 Bean 名稱。而@Resource
默認(rèn)按照屬性名進(jìn)行裝配,可以通過 name 屬性指定具體的 Bean 名稱。@Autowired
是 Spring 的專有注解,更加靈活,功能更強(qiáng)大。@Resource
是標(biāo)準(zhǔn)的 Java 注解,適用于更通用的情況@Autowired
可用于Setter
注入、構(gòu)造函數(shù)注入和屬性注入,而@Resource
只能用于Setter
注入和屬性注入,不能用于構(gòu)造函數(shù)注入。
2.6 注入同一類型的多個(gè) @Bean 報(bào)錯(cuò)問題
當(dāng)存在多個(gè)類型相同的 Bean 對(duì)象,并且需要通過注解將其注入到其他 Bean 對(duì)象中時(shí),如果沒有明確指定注入哪個(gè) Bean,就會(huì)導(dǎo)致報(bào)錯(cuò)。
2.6.1 報(bào)錯(cuò)問題
例如,通過 Component 中的 UserBeans
將 User 注入到 Controller 中的 UserController
中。
首先,在 UserBeans
使用 @Bean
添加兩個(gè) User 對(duì)象到 Spring 容器中:
@Controller public class UserBeans { @Bean(name = {"user1", "u1"}) public User getUser1(){ User user = new User(); user.setUid(1); user.setUsername("張三"); user.setPassword("123456"); user.setAge(18); return user; } @Bean(name = "user2") public User getUser2(){ User user = new User(); user.setUid(1); user.setUsername("李四"); user.setPassword("123456"); user.setAge(18); return user; } }
在 UserController
中分別使用 @Autowired
和 @Resource
注入獲取 Bean 對(duì)象:
@Autowired
:
此時(shí),由于存在兩個(gè)相同類型的 Bean 對(duì)象,但是其名稱不同,所以使用 @Autowired
注解不知道獲取哪個(gè)對(duì)象。
@Resource
使用 @Resource
注解同樣無法判斷獲取哪一個(gè)對(duì)象。
關(guān)于
@Autowired
和@Resource
查找 Bean 對(duì)象的順序:@Autowired
首先按照類型查找,然后再按照名稱查找;@Resource
首先按照名稱查找,然后再按照類型查找。
2.6.2 使用 @Resource(name=“XXX”) 解決
@Controller public class UserController { @Resource(name = "user1") private User user; public void sayHi(){ System.out.println("do userController sayHi()."); } }
2.6.3 @Autowired 配合使用 @Qualifier 解決
@Controller public class UserController { @Autowired @Qualifier(value = "user1") private User user; public void sayHi() { System.out.println("do userController sayHi()."); } }
到此這篇關(guān)于Spring 使用注解存儲(chǔ)和讀取 Bean對(duì)象的文章就介紹到這了,更多相關(guān)Spring注解存儲(chǔ)和讀取 Bean對(duì)象內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java并發(fā)編程volatile關(guān)鍵字的作用
這篇文章主要介紹了Java并發(fā)編程volatile關(guān)鍵字的作用,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07Mybatis-plus與Mybatis依賴沖突問題解決方法
,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧這篇文章主要介紹了Mybatis-plus與Mybatis依賴沖突問題解決方法2021-04-04JDK源碼分析之String、StringBuilder和StringBuffer
這篇文章主要給大家介紹了關(guān)于JDK源碼分析之String、StringBuilder和StringBuffer的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用jdk具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05