Spring?使用注解存儲和讀取?Bean對象操作方法
前言
前面的文章詳細的介紹了 Spring 對象的創(chuàng)建,以及對 Bean 對象的存取操作,但是通過配置文件注冊 Bean 對象以及使用 ApplicationContext 或 BeanFactory 的方式獲取 Bean 對象的操作就顯得格外的復(fù)雜。因此,本文主要就是詳細介紹了一種更加簡單的方式來實現(xiàn)對 Bean 對象更加簡單的儲存和讀取操作。
在 Spring 中,要想更加簡單的實現(xiàn)對 Bean 對象的儲存和使用,其核心就是使用 注解 ,本文主要就是演示如何使用注解實現(xiàn)對 Bean 對象的存取操作。
一、使用注解儲存 Bean 對象
在之前儲存 Bean 對象的時候,還需在 spring-congig 文件中添加一行 <bean> 內(nèi)容才行,而且,每需要新增一個 Bean 對象到 Spring 容器中就需要新增一行,這樣的操作就顯得非常麻煩了。
而現(xiàn)在只需要使用一個 注解 就能代替這一行 <bean> 內(nèi)容,此時就變得非常方便。想要通過注解的方式將對象儲存到 Spring 容器中,主要有兩種注解類型可以實現(xiàn):
1.使用類注解(五大類注解):
@Controller(控制儲存):驗證用戶請求的數(shù)據(jù)合法性,相當(dāng)于安保系統(tǒng);@Service(服務(wù)儲存):用于編排和調(diào)度具體的執(zhí)行方法;@Repository(倉庫儲存):持久層,與數(shù)據(jù)庫進行交換;@Component(組件儲存):相當(dāng)于工具類;@Configuration(配置儲存):項目中的一些配置。
2.使用方法注解:
@Bean:作用在方法上,需要配合上述的類注解使用。
但在此之前還需要配置一下 掃描路徑 。
1.1 配置掃描路徑
在 spring-config.xml 文件中添加如下一行記錄:

其含義是,指定一個 base package ,即所有需要添加到 Spring 容器中的 Bean 對象都在 base package 所指定包或者其子包下。這里我知道的包是 com.spring.demo ,那么就意味著,如果不是此包下的 Bean 對象,即使加上了注解,也不會被添加到 Spring 容器中。
1.2 類注解儲存 Bean 對象
1.2.1 @Controller(控制器存儲)
使用 @Controller 注解儲存 Bean 對象:
@Controller
public class StudentController1 {
public void sayHi(){
System.out.println("do studentController1 sayHi().");
}
}使用 ApplicationContext 的方式獲取 Bean 對象:
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 對象的命名規(guī)則可見后文。
1.2.2 @Service(服務(wù)儲存)
使用 @Service 注解儲存 Bean 對象:
@Service
public class StudentController2 {
public void sayHi(){
System.out.println("do studentController2 sayHi().");
}
}獲取 Bean 對象:
StudentController2 studentController2 =
context.getBean("studentController2", StudentController2.class);1.2.3 @Repository(倉庫存儲)
使用 @Repository 注解儲存 Bean 對象:
@Repository
public class StudentController3 {
public void sayHi(){
System.out.println("do studentController3 sayHi().");
}
}獲取 Bean 對象:
StudentController3 studentController3 =
context.getBean("studentController3", StudentController3.class);1.2.4 @Component(組件儲存)
使用 @Component 注解儲存 Bean 對象:
@Component
public class StudentController4 {
public void sayHi(){
System.out.println("do studentController4 sayHi().");
}
}獲取 Bean 對象:
StudentController4 studentController4 =
context.getBean("studentController4", StudentController4.class);1.2.5 @Configuration(配置儲存)
使用 @Configuration 注解儲存 Bean 對象:
@Configuration
public class StudentController5 {
public void sayHi(){
System.out.println("do studentController5 sayHi().");
}
}獲取 Bean 對象:
StudentController5 studentController5 =
context.getBean("studentController5", StudentController5.class);1.2.6 Bean 命名規(guī)則
通過上述代碼可以發(fā)現(xiàn),在創(chuàng)建 Bean 對象的時候,都是使用的標準 “大駝峰” 的命名方式,而讀取的時候 Bean 的名稱則是其類名稱的首字母小寫,即小駝峰。

但是,此時創(chuàng)建一個 SController 類,并使用注解將其添加到 Spring 容器中,那么此時它的 Bean 對象的名稱是什么呢?根據(jù)上面代碼的規(guī)律,難道還是 SController 嗎?
SController sController = context.getBean("sController", SController.class);當(dāng)運行程序的時候,發(fā)現(xiàn)報錯了:

其意思是不存在名稱為 sController 這樣 Bean 對象。此時如果將其改成 SController ,會是正確的嗎?

此時發(fā)現(xiàn)便能正常運行了。
關(guān)于 Bean 的名稱生成的源碼:
查找 beanname,選擇 AnnotationBeanNameGenerator 類

繼續(xù)查找

繼續(xù)查找

4. 找到了源碼,即 Introspector 類下的 decapitalize 方法

該方法通過檢查字符串的首字母是否為大寫,并且第二個字符也是大寫的情況下,直接返回原字符串,不做小寫化處理。這樣做是為了避免一些特殊情況下,例如縮寫或首字母縮寫詞,不被誤處理。
1.3 五大類注解的作用
在Spring框架中,五大類常用的注解,分別是:@Component、@Controller、@Service、@Repository和@Configuration。
@Component: 通用的組件注解,表示類是一個Spring管理的組件(Bean)。@Controller: 用于標識控制器類,通常用于Spring MVC中,處理HTTP請求和視圖渲染。@Service: 用于標識服務(wù)類,表示該類提供一些業(yè)務(wù)邏輯處理。@Repository: 用于標識倉庫類,表示該類用于數(shù)據(jù)訪問,通常與數(shù)據(jù)庫交互。@Configuration: 用于標識配置類,表示該類包含Spring配置信息,通常與@Bean一起使用,用于定義 Bean。
1.3.1 為什么有這么多的注解
通過上面代碼的演示,發(fā)現(xiàn)這些注解的功能都是一樣的,既然都是一樣的為什么還需要有這么多不同的注解呢?
Spring 之所以提供這么多的注解,是為了更好的組織和管理應(yīng)用程序的組件和依賴關(guān)系。因為每個注解都有自己特定的用途,讓開發(fā)人員在應(yīng)用程序中能夠更方便地標識和區(qū)分不同類型的類。同時也提現(xiàn)了程序的工程分層:

- 其中
@Controller表示的是控制層,負責(zé)與用戶進行交互,以及驗證用戶提交數(shù)據(jù)的合法性; @Service表示的是服務(wù)層,用于編排和調(diào)度具體的執(zhí)行方法,相當(dāng)于車站中的服務(wù)臺;@Repository表示的是持久層,負責(zé)將數(shù)據(jù)持久化儲存,通常需要與數(shù)據(jù)庫進行交互。
以上三個層次實現(xiàn)了程序的工程分層,同時也是 Java EE 標準分層的最核心分層。
1.3.2 類注解之間的關(guān)系
查看 @Controller / @Service / @Repository / @Configuration 等注解的源碼發(fā)現(xiàn):

它們都是 @Component 子類注解,這意味著,被標注為 @Controller / @Service / @Repository / @Configuration 的類也被視為 @Component 。
- 另外,
@Configuration注解是一個特殊的注解,它表明該類是 Spring 的配置類,用于定義 Bean 和配置應(yīng)用程序的其他元素。配置類中的@Bean注解用于定義 Bean。
1.4 方法注解儲存 Bean 對象
首先創(chuàng)建一個 User 實體類:
package com.spring.demo.entity;
/**
* 普通的用戶實體類
*/
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)建一個組件類 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 的時候需要搭配五大類注解才能生效。
獲取 Bean 對象:
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 的時候,Bean 對象的默認名稱就是其 添加到 Spring 容器中的方法名。
1.4.2 Bean 對象重命名
如果直接使用方法名作為 Bean 對象的名稱,例如 getUser 就顯得非常的不合理,因此往往需要對 Bean 進行改名操作。但查看 @Bean 源碼的時候可以發(fā)現(xiàn),其中的 name 或 value 屬性是一個數(shù)組,那么就意味著可以一個 Bean 對象取多個名稱。

例如:

此時,可通過這兩個名稱,獲取該 Bean 對象,發(fā)現(xiàn)它們是同一個 Bean:

另外需要注意的是,如果對 Bean 進行了重命名,則原來默認的方法名就失效了。

二、使用注解獲取 Bean 對象
2.1 Bean 對象通過注解獲取的方法
獲取 Bean 對象也叫做 對象裝配 ,即把對象取出來放到某個類當(dāng)中,同時也叫做 對象注入 。
對象注入的實現(xiàn)方式有以下三種:
- 屬性注入:屬性注入是通過在屬性上使用注解實現(xiàn)的。常見的注解有
@Autowired和@Resource。屬性注入是在 Bean 對象的屬性上直接進行注入,不需要提供setter方法。 Setter注入:Setter注入是通過在 Bean 對象的setter方法上使用注解實現(xiàn)的。這種注入方式是在調(diào)用 Bean 的setter方法時,將依賴對象作為參數(shù)傳入。- 構(gòu)造方法注入:構(gòu)造方法注入是通過在 Bean 對象的構(gòu)造方法上使用注解實現(xiàn)的。這種注入方式是在創(chuàng)建 Bean 對象的時候,通過構(gòu)造方法參數(shù)傳入依賴對象。
2.2 三種注入方法的使用
下?按照實際開發(fā)中的模式,將 Service 類注入到 Controller 類中,然后通過 main 方法獲取 Controller 中的 Bean 對象。首先創(chuàng)建一個 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();
}
}注意,如果此時只有一個構(gòu)造方法,則 @Autowired 可以省略。
2.3 三種注入方法的優(yōu)缺點
屬性注入
- 優(yōu)點:簡潔,代碼量少,適合對屬性直接注入的情況;
- 缺點:
- 對于必須注入的屬性,如果沒有找到匹配的Bean,會導(dǎo)致運行時錯誤;
- 兼容不好,只能用于 IoC 容器;
- 沒辦法實現(xiàn)
finally修飾的變量實現(xiàn)注入; - 過于簡單,容易違背單一設(shè)計原則。
Setter注入:
- 優(yōu)點:符合單一設(shè)計原則,每個方法只能傳遞一個對象。
- 缺點:
- 沒辦法實現(xiàn)
finally修飾的變量實現(xiàn)注入; - 使用 Setter 注入的對象可能會被修改。
- 沒辦法實現(xiàn)
構(gòu)造方法注入:
- 優(yōu)點:
- 可以實現(xiàn)
finally修飾的變量實現(xiàn)注入; - 注入的對象不會被改變,即構(gòu)造方法只能執(zhí)行一次;
- 構(gòu)造方法注入可以保證注入對象完全被初始化。
- 可以實現(xiàn)
- 缺點:構(gòu)造方法參數(shù)較多時,代碼顯得冗長。
2.4 @Resource 注入
在進行類注入時,除了可以使用 @Autowired 關(guān)鍵字之外,我們還可以使用 @Resource 進行注入,如下代碼所示:
屬性注入:
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 也對其進行了支持。@Autowired默認按照類型裝配 Bean,如果多個類型匹配,可以配合@Qualifier注解指定具體的 Bean 名稱。而@Resource默認按照屬性名進行裝配,可以通過 name 屬性指定具體的 Bean 名稱。@Autowired是 Spring 的專有注解,更加靈活,功能更強大。@Resource是標準的 Java 注解,適用于更通用的情況@Autowired可用于Setter注入、構(gòu)造函數(shù)注入和屬性注入,而@Resource只能用于Setter注入和屬性注入,不能用于構(gòu)造函數(shù)注入。
2.6 注入同一類型的多個 @Bean 報錯問題
當(dāng)存在多個類型相同的 Bean 對象,并且需要通過注解將其注入到其他 Bean 對象中時,如果沒有明確指定注入哪個 Bean,就會導(dǎo)致報錯。
2.6.1 報錯問題
例如,通過 Component 中的 UserBeans 將 User 注入到 Controller 中的 UserController 中。
首先,在 UserBeans 使用 @Bean 添加兩個 User 對象到 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 對象:
@Autowired :

此時,由于存在兩個相同類型的 Bean 對象,但是其名稱不同,所以使用 @Autowired 注解不知道獲取哪個對象。
@Resource

使用 @Resource 注解同樣無法判斷獲取哪一個對象。
關(guān)于
@Autowired和@Resource查找 Bean 對象的順序:@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 使用注解存儲和讀取 Bean對象的文章就介紹到這了,更多相關(guān)Spring注解存儲和讀取 Bean對象內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
比較java中Future與FutureTask之間的關(guān)系
在本篇文章里我們給大家分享了java中Future與FutureTask之間的關(guān)系的內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)下。2018-10-10
Spring的同一個服務(wù)會加載多次的問題分析及解決方法
這篇文章主要介紹了Spring的同一個服務(wù)為什么會加載多次,我們先來梳理一下?Web?容器中如何加載?Bean,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-10-10
Spring的兩種事務(wù)管理機制的基本概念和demo示例
Spring事務(wù)包括聲明式事務(wù)管理和注解式事務(wù)管理,我們通過概念和小demo的形式一步一步地來一起學(xué)習(xí)這個知識點,需要的朋友可以參考下2023-07-07
JAVA使用commos-fileupload實現(xiàn)文件上傳與下載實例解析
這篇文章主要介紹了JAVA使用commos-fileupload實現(xiàn)文件上傳與下載的相關(guān)資料,需要的朋友可以參考下2016-02-02

