Spring IoC(控制反轉)之常用注解
1. 前言
上一節(jié),我們通過注解的方式,實現(xiàn)了 Spring 對于 bean 的管理,那么如何實現(xiàn)的,是否還記得呢,我們回顧一下
兩個重要點:
1. 注解實例化的類上,需要使用一個注解 @Repository
;
2.Spring 的配置文件中,需要使用組件掃描 <context:component-scan>
。
疑問導出:
組件掃描的作用我們清楚,是為了掃描路徑之下帶有注解的類,但是為什么類上面的注解是 @Repository
呢?或者說,是否還有其余的注解可以實現(xiàn)呢?
本節(jié),我們一起來學習下 Spring IoC 的常用注解。
2. 注解的詳解
在我們詳細講解注解之前,首先明確一點:
注解配置和 xml 配置實現(xiàn)的功能都是一樣的,只不過實現(xiàn)的方式不同,那么也就是說,xml 文件可以實現(xiàn)的,通過注解都可以完全辦得到。比如實例化對象,設置屬性,設置作用范圍,生命周期的方法執(zhí)行等等…
2.1 注解分類介紹
按功能劃分:
- 創(chuàng)建對象: 對應的就是在 xml 文件中配置的一個 bean 標簽,可以定義 id、name、class 等屬性;
- 注入數據: 對應的就是在 bean 標簽下,使用 property 標簽給類中的依賴屬性賦值;
- 作用范圍: 對應的就是設置 bean 標簽的 scope 屬性,不設置默認也是單例;
- 生命周期: 對應的就是設置 bean 標簽的 init-method 和 destroy-method 方法。
2.1.1 創(chuàng)建對象的注解介紹
從 Spring 的官網得知一段話:
@Repository
注釋是針對滿足的存儲庫(也被稱為數據訪問對象或 DAO)的作用,或者固定型的任何類的標記。
也就是說,我們上一節(jié)中使用的注解,一般用于 dao 層使用。那么,我們都知道,JAVAEE 體系結構,一般開發(fā)分為三個層級:
- 表現(xiàn)層: 主要作用為處理數據生成靜態(tài)的頁面響應給瀏覽器展示 ;
- 業(yè)務層: 主要作用為業(yè)務邏輯代碼編寫,數據的獲取,數據的封裝返回等等操作都在這里;
- 持久層: 主要作用為跟數據庫打交道,對于數據的持久化操作等。
那么,如果是創(chuàng)建的表現(xiàn)層或者業(yè)務層代碼,應該使用什么注解呢?
好了,看一下創(chuàng)建對象注解的劃分:
- @Component :一般用于通用組件的類上使用的注解;
- @Service : 一般用于業(yè)務層類上使用的注解;
- @Controller : 一般用于控制層類上使用的注解;
- @Repository :一般用于持久層類上使用的注解。
官網解釋:
Spring 提供進一步典型化注解:
@Component
,@Service
,和@Dao
。
@Component
是任何 Spring 托管組件的通用構造型。
@Repository
,@Service
和@Controller
是@Component
針對更特定用例的專業(yè)化(分別在持久性,服務和表示層)。
慕課解釋:
@Component
注解是 Spring 框架中通用的一個注解,用于組件掃描實例化對象使用, 那么其余的三個注解 @Controller
,@Service
,@Repository
都是 @Component
注解的衍生注解,作用跟 @Componet
注解的作用一致。
那么意義在于, 三個注解,對應的是三個開發(fā)層級 ,一般來講我們將 @Controller
作為表現(xiàn)層的使用,@Service
作為業(yè)務層的注解,@Repository
作為持久層使用的注解。我們下面通過案例演示一下。
2.2 創(chuàng)建對象的注解
實例說明
四種注解的測試,本節(jié)重點講解創(chuàng)建對象使用的注解,而作用范圍 scope 和生命周期的兩個注解,我們放在后續(xù)對應的小節(jié)進行講解測試。
置于注入數據的注解,是比較重要的一個內容, 我們放在依賴注入這節(jié)詳細講解。
各位同學… 稍安勿躁,我們一起慢慢成長。
創(chuàng)建工程省略
我們繼續(xù)使用上一節(jié)的注解工程實例即可,那么為了演示三個注解,我們分別創(chuàng)建三個層級對應的代碼:
- 表現(xiàn)層的
UserController
- 業(yè)務層的
UserService
- 實現(xiàn)類
UserServiceImpl
持久層 dao 代碼已經創(chuàng)建過了,這里不多解釋。創(chuàng)建好的所有代碼如下:
UserController 代碼:
@Controller
public class UserController {
public void saveUser(){
System.out.println("這是controller的執(zhí)行保存..");
}
}
UserService 和實現(xiàn)類代碼:
public interface UserService {
public void saveUser();
}
@Service
public class UserServiceImpl implements UserService {
public void saveUser() {
System.out.println("執(zhí)行service中的保存邏輯");
}
}
項目結構如下:
上面是本案例的工程以及代碼結構:
? 類雖然看起來很多,實際沒有業(yè)務邏輯代碼,只不過在各個層級使用了三個注解來注入到容器,目的是測試當 Spring 的配置文件加載掃描后,是否可以從容器中獲取三種注解(@Controller
@Service
@Repository
)注入的 bean 對象。
Tips: Spring 的配置文件
context:component-scan
標簽的掃描層級 需要包含三個包路徑,例如我的工程實例代碼如下:
<context:component-scan base-package="com.wyan"></context:component-scan>
測試類與測試結果:
結論:
可以三個注解都可以將對象注入到 Spring 的容器,那么以后開發(fā)時候按照規(guī)范或者習慣,分層開發(fā),使用對應的注解。但它并不是必須這么做,你使用任意一種都可以,只不過,代碼的可讀性會差。
所以,我們一般表現(xiàn)層使用 @controller
,業(yè)務層使用 @service
, 持久層使用 @Repository
。
至于 @Component
如果有其余的類,不屬于三個層級,可以采用 @Component
作為通用組件掃描注入容器。
2.3 注解注入規(guī)則
剛剛通過三個注解都可以完成了 bean 的實例化注入,通過測試代碼也獲取到了容器中的三個對象實例,那么這里不知道大家是否發(fā)現(xiàn)一個問題:
我們知道,Spring 這個容器本質是個 map 集合來存儲實例化后的對象。既然是個 map 集合,就應該對應的有 key 和 value。
我們都知道 value 肯定是實例化后的 bean ,那么 key 是什么呢?
注入規(guī)則:
1. 四種注解都支持 value 的屬性作為自定義的 bean id ;
2. 如果 value 屬性沒有指定,那么默認以類的簡單名稱(類名首字母小寫)作為 bean 對象的 id。
所以我們可以看到:
當我們只使用注解沒有自定義 id 的時候可以通過,每個類的首字母小寫來獲取對象實例,那么如果有了自定義的 id,上述代碼是否繼續(xù)可用呢?
自定義 id 獲取實例:
改造類上面的注解,設置自定的 id,更改的注解如下:
@Controll("uc")
@Service("us")
@Repository("ud")
測試結果:
測試結果:
為了區(qū)分測試結果,我在測試代碼中,只修改了 controller 的獲取方式,將 id 改成了 uc 。service 和 dao 并沒有修改。
從控制臺打印可以看到,只有 controller 對象可以成功獲取,service 和 dao 都失敗了,因為我們已經使用了自定義的 id,所以容器中沒有默認的以類名作為 id 的 bean 對象實例。
3. 小結
本章節(jié)重點講解注解的使用:
- Spring 支持的注解有四種分類;
- Spring 創(chuàng)建對象的注解四種分類;
- Spring 創(chuàng)建對象注入容器的規(guī)則。
學習的苦只是一時之苦,學不到的苦是一世之苦,與君共勉…