1. 程式人生 > >Spring進階案例之註解和IoC案例

Spring進階案例之註解和IoC案例

#### 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 /** 查詢所有 */