Spring進階案例之註解和IoC案例
阿新 • • 發佈:2020-07-30
#### Spring進階案例之註解和IoC案例
##### 一、常見的註解分類及其作用
從此前的基於xml的IoC開發案例和依賴注入案例中,我們可以將xml配置歸納為:
```xml
```
註解按照作用可以分為四類:
###### 1.用於建立物件的註解:相當於xml配置的bean標籤
建立物件的註解有如下幾個:
| 註解 | 作用 | 屬性 |
| :---------: | :--------------------------: | :----------------------------------------------------------: |
| @Component | 把當前類物件存入Spring容器中 | value: 用於指定bean的id。當不寫value屬性時,預設值是當前類名,且首字母改小寫 |
| @Controller | 一般用在表現層建立bean | 同上 |
| @Service | 一般用在業務層建立bean | 同上 |
| @Repository | 一般用在持久層建立bean | 同上 |
最後三個註解的作用和屬性與Component註解一模一樣,他們是Spring框架為我們提供明確三層架構的註解,可以使三層架構更加清晰。
如果我們在AccoutServiceImpl類上加上@Component("accountService")或者@Service("accountService"),都可以起到將AccountServiceImpl類的物件加入的IoC容器中的效果。此時,ui.Client類中的main方法還不能執行:
```java
public static void main(String[] args) {
//驗證依賴注入
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
System.out.println(accountService);
}
```
會顯示No bean named 'accountService' ,這是因為我還沒有對Spring要掃描的包進行配置,如果不配置,Spring是不知道哪些類需要掃描註解。
```xml
```
此時,專案結構為:
```txt
dao包:
public interface IAccountDao
dao.impl包:
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao
service包:
public interface IAccountService
service.impl包:
@Service("accountService")
public class AccountServiceImpl implements IAccountService
ui包:
public class Client
```
###### 2.用於注入物件的註解:相當於xml配置的bean標籤中property標籤,使用註解進行注入時,不再需要set方法
如果我們需要呼叫accountService中的saveAccount方法,就需要對AccountServiceImpl類中的accountDao成員變數進行注入。同時需要在AccountDaoImpl類的accountDao變數上加上@Autowired("accountDao")註解。用於注入資料的註解有如下幾個:前三個註解只能注入其他bean型別的注入,基本型別和String型別的注入無法通過它們來實現。集合型別的注入只能通過xml配置來實現,不能通過註解來實現。
| 註解 | 作用 | 屬性 |
| :--------: | :----------------------------------------------------------: | :----------------------------------------------------------: |
| @Autowired | 自動按照型別注入,可以出現在變數上,也可以出現在在方法上。 | 無 |
| @Qualifier | 按照類中注入的基礎之上再按照名稱注入。在給類成員注入時不能單獨注入,在給方法引數注入時可以單獨注入 | value:用於指定注入bean的id |
| @Resource | 直接按照bean的id注入,可以單獨使用 | name:用於指定注入bean的id |
| @Value | 用於注入String型別和基本型別 | value:用於指定注入資料的值,可以使用Spring中的el表示式(SpEL,寫法為:${表示式}) |
這個時候,我們在ui.Client類的main方法中,就可以執行saveAccount方法了。
```java
public static void main(String[] args) {
//驗證依賴注入
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
System.out.println(accountService);
IAccountDao accountDao = applicationContext.getBean("accountDao", IAccountDao.class);
System.out.println(accountDao);
//呼叫saveAccount方法
accountService.saveAccounts();
}
```
在使用@Autowired註解時,需要注意的是:
1. 只要IoC容器中有唯一的一個bean物件和要注入的變數型別匹配,就可以注入成功。
2. 如果IoC容器中任何bean物件和要注入的變數型別都不匹配,就會報錯。
3. 如果IoC容器中有多個bean物件和要注入的變數型別匹配,則按變數名稱和bean類名進行匹配,若有唯一一個匹配,則注入成功,否則注入失敗。
例如,在dao.impl包下,有兩個IAccountDao介面的實現類,分別是是AccountDaoImpl1和AccountDaoImpl2,在這兩個類上分別加入註解@Repository("accountDao1")和@Repository("accountDao2")。
此時,專案結構為:
```txt
dao包:
public interface IAccountDao
dao.impl包:
@Repository("accountDao1")
public class AccountDaoImpl1 implements IAccountDao
@Repository("accountDao2")
public class AccountDaoImpl2 implements IAccountDao
service包:
public interface IAccountService
service.impl包:
@Service("accountService")
public class AccountServiceImpl implements IAccountService
ui包:
public class Client
```
如果還使用Autowired註解對AccountServiceImpl類中的accountDao變數進行注入,就會報錯。這個時候,有三種方式可以選擇:
* 只使用@Autowired註解,並修改accountDao變數名為accountDao1,此時注入的是dao.impl.AccountDaoImpl1
* 同時使用@Autowired和@Qualifier("accountDao2")註解,變數名可以任意,注入的是dao.impl.AccountDaoImpl2
* 只使用@Resource(name = "accountDao1")註解,變數名可以任意,注入的是dao.impl.AccountDaoImpl1
```java
//方法一
@Autowired
private IAccountDao accountDao1;
//方法二
@Autowired
@Qualifier("accountDao2")
private IAccountDao accountDao22;
//方法三
@Resource(name = "accountDao1")
private IAccountDao accountDao;
```
為了看的更清楚,我們進行如下改造:
```java
//AccountDaoImpl1和AccountDaoImpl2中的saveAccounts方法:
public void saveAccounts() {
System.out.println(this.getClass());
System.out.println("向資料庫寫入賬戶資料!!!");
}
//AccountServiceImpl中的saveAccounts方法:
public void saveAccounts() {
System.out.println("執行儲存賬戶操作");
//呼叫持久層介面函式
accountDao.saveAccounts();
accountDao1.saveAccounts();
accountDao22.saveAccounts();
}
//Client類中的main方法:
public static void main(String[] args) {
//驗證依賴注入
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
//呼叫saveAccount方法
accountService.saveAccounts();
}
```
輸出為:
```txt
執行儲存賬戶操作
class dao.impl.AccountDaoImpl1
向資料庫寫入賬戶資料!!!
class dao.impl.AccountDaoImpl1
向資料庫寫入賬戶資料!!!
class dao.impl.AccountDaoImpl2
向資料庫寫入賬戶資料!!!
```
###### 3.用於改變物件作用範圍的註解:相當於xml配置的bean標籤中的scope屬性
如果我們要改變bean的作用範圍,就需要用到scope屬性:
| 註解 | 作用 | 屬性 |
| :----: | :--------------------: | :----------------------------------------------------------: |
| @Scope | 用於指定bean的作用範圍 | value: 指定範圍的取值。常用取值:singleton(單例,也是預設值)、prototype(多例)、 |
例如,我們在AccountServiceImpl2類上加上註解@Scope("prototype"),然後在main方法中執行:
```java
IAccountDao accountDao11 = applicationContext.getBean("accountDao1", IAccountDao.class);
System.out.println(accountDao11);
IAccountDao accountDao12 = applicationContext.getBean("accountDao1", IAccountDao.class);
System.out.println(accountDao12);
IAccountDao accountDao21 = applicationContext.getBean("accountDao2", IAccountDao.class);
System.out.println(accountDao21);
IAccountDao accountDao22 = applicationContext.getBean("accountDao2", IAccountDao.class);
System.out.println(accountDao22);
```
可以看到輸出中,前兩個accountDao是同一個物件,後兩個是不同物件:
![驗證@Scope註解](https://tva1.sinaimg.cn/large/007S8ZIlgy1gh151nfnx5j30a702zq38.jpg)
###### 4.用於改變物件生命週期的註解:相當於xml配置的bean標籤中的init-method屬性和destroy-method屬性
| 註解 | 作用 | 使用位置 |
| :------------: | :----------------: | :--------: |
| @PostConstruct | 用於指定初始化方法 | 用在方法上 |
| @PreDestroy | 用於指定銷燬方法 | 用在方法上 |
注意:多例物件的銷燬仍然由JVM執行,無法通過關閉容器來銷燬
###### 二、基於XML的IoC案例
###### 1.準備工作
這個IoC案例,主要演示對資料庫的crud操作,所以首先需要建立資料庫,sql檔案如下:
```sql
create table account(
id int primary key auto_increment,
name varchar(40),
money float
)character set utf8 collate utf8_general_ci;
insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);
```
整個專案的結構如下:
![基於xml的IoC案例的專案結構](https://tva1.sinaimg.cn/large/007S8ZIlgy1gh8ryifnjyj30ac0b8jrx.jpg)
IAccountDao和IAccountService這兩個介面類中的方法如下,因為只是演示,簡單起見這兩個介面中的方法一模一樣:
```java
/** 查詢所有 */