1. 程式人生 > >Spring IOC詳細配置與使用

Spring IOC詳細配置與使用

前言:複習瞭解下Spring,順便記錄下這個過程以供日後翻閱。本篇將從Spring IOC的xml以及annotation兩種配置進行。

SpringIOC:

    按照我個人的理解來說,SpringIOC(Inversion of Control)控制反轉:指就是說原先在物件中要使用另一個物件就必須要顯式的去建立另一個物件的例項,例如通過構造方法或者是呼叫工廠方法(工廠方法最終也是需要new,因為這是Java建立物件所必須的)來獲得。而Spring提供了IOC容器來幫我們生成所需要的物件。也就是說在我們原先的物件中有用到其他物件的地方Spring會幫我們來注入。不用我們再去考慮這些問題。這邊注入的實現手段就是DI(Dependency Injection)依賴注入。DI的方式有兩種,一種是通過配置檔案XML,一種是通過註解Annotation。下面會為兩種進行說明。本次採用的結構目錄可以參考

基於SpringMVC+Spring+Hibernate+Maven+Bootstrap的簡單Demo或者是SpringMVC整合Mybatis+Maven+Bootstrap的簡單Demo

SpingIOC容器:

    容器所為SpringIOC的核心它主要有兩種:

BeanFactory:BeanFactory為IOC容器提供了基礎功能,Spring文件中提到,當前該類僅僅是為了向後相容老的版本,除非你有更好的原因否則就應該使用第二種容器。

ApplicationContext:通過API文件可以知道,ApplicationContext是BeanFactory的子介面,並且從文件中也可以看到ApplicaionContext除了包含有BeanFactory的所有功能還支援了更多的功能。

ApplicationContext的實現有四種方式:

FileSystemXmlApplicationContext:載入配置檔案的時候採用的是專案的路徑。

ClassPathXmlApplicationContext:載入配置檔案的時候根據ClassPath位置。

XmlWebApplicationContext:在Web環境下初始化監聽器的時候會載入該類。

AnnotationConfigApplicationContext:根據註解的方式啟動Spring 容器。

SpringDI的方式:

    Spring提供了三種方式來依賴注入,有構造方法注入,setter方法注入以及介面注入(屬性)。其中Spring以往推薦使用Setter的方法現在改成推薦構造方法注入。使用構造方法注入需要注意的一點就是要避免迴圈依賴。所謂的迴圈依賴指的就是在A物件的構造方法中Spring要注入B,而在B物件中Spring要注入A。這個時候會形成一個閉環因為Spring不知道該先注入哪一個接著會丟擲異常。而Spring建議的處理方式是說如果遇到這種情況的話就改用Setter方式注入。

SpringIOC之Xml:

    Bean:

    省去了所有的測試環境的搭建本次使用Junit進行單元測試使用ClassPathXmlApplication來管理bean。首先從把類交給Spring Ioc管理開始一步步深入。從下面例項可以看到我們要讓Spring幫我們管理物件的生成需要在配置檔案中進行註冊。每一個標籤bean對應的就一個類物件,通過id(或者Name)以及Class來定位一個類,這邊Class要求是完全限定類名。因為Spring生成物件的過程就是使用反射機制所以你必要要提供一個正確的路徑否則就會丟擲異常。除了這兩個屬性外,Spring還提供了其他的屬性來對Bean進行設定下面將對所有的屬性進行測試。

   abstract以及parent:

   abstract以及parent是搭配使用的,如果bean定義了屬性abstact=true,那麼這個類就無法通過Spring容器拿到,而是作為一個模板存在。有點類似於設計模式中的模板方法。這個bean對應的類它定義的屬性,方法可以被複用。通過Parent屬性在子類中可以指向被abstract定義的bean。用法包括集合類的並集,類的繼承等等。下面給出栗子,可以看到定義了一個父類UserAbstract還有它的子類UserExtendsAbs。執行的時候子類可以直接拿到父類中定義的屬性name以及age。此外Spring允許我們對父類中的值進行覆蓋,所以Name輸出變成了test2。

    lazy-init,init-method,destroy-method:

    預設情況下容器中的所有bean在初始化容器的時候就被載入,但是我們可以指定lazy-init屬性來讓Spring實現懶載入。只有在呼叫的時候才新增進容器。而init-method以及destory-method顧名思義就是初始化以及銷燬的時候呼叫,類似於Servlet的init以及destory。下面舉個栗子。因為UserServiceImpl跟UserDaoImpl有關聯關係所以註釋掉。可以看到程式開始容器初始化的時候沒有對userDaoImpl初始化,而當呼叫了userDaoImpl的時候才會被加入容器裡面。此時也可以看到init方法被呼叫,在容器關閉的時候destory也被呼叫了。

    depends-on:

    一般情況下如果兩個物件存在依賴的時候我們會通過上述提到的三種注入方式來注入。但是如果兩個物件的關係沒有那麼直接,例如A物件在初始化的時候要呼叫B物件的一個靜態引數,而這個靜態引數只有B初始化的時候才會更新。而它們直接的依賴關係並沒有那麼直接。那麼這個時候我們就可以使用depends-on。舉個栗子。可以看到預設情況下userDaoImpl拿到number為0,而添加了depends-on後,Spring會先初始化userDaoImpl2然後再初始化userDaoImpl,所以number的值變成了10。


    factory-bean,factory-method:

    Spring除了通過class來拿到物件,同時也允許物件通過工廠的方法來獲取。舉個栗子。可以看到userDaoImpl通過DaoFactory工廠拿到。


 

    Scope:

    Spring的bean可以設定scope屬性來確認它的作用域,可以看到預設情況下是singleton也就是單例,也可以設定成多例。而其他的幾種情況都是在web環境下使用。舉個栗子。可以看到預設情況下每次取出來的userDaoImpl都是同一個,而我們如果設定成prototype那麼每次拿到的物件都是不一樣的。

在介紹剩下的autowire,autowire-candidate以及primary屬性之前,先介紹了xml中如何實現依賴注入。

    構造器注入:

    直接舉個栗子。現在我們要在物件userServiceImpl中注入物件userDaoImpl。如果我們沒有指定的話,預設情況下是呼叫預設的構造方法來初始化。可以看到屬性值通過構造方法成功注入,這邊Spring允許你通過name來對應構造器引數,也可以使用index表示對應的位置,從0開始。或者使用type,指定型別。


    setter方法注入:

    直接舉個栗子。之前的例子通過構造方法注入,現在我們直接使用標籤property的方式來注入。可以看到一樣可以注入成功。但是切記,所以的成員變數必須實現它的setter方法,否則會丟擲異常。

    Collection注入:

    在物件中經常要使用到Collection集合型別,Spring也提供了物件的方式來注入。舉個栗子。


現在回過頭來說說前面擱置的幾個屬性。

   autowire:

    Spring有個自動裝配的機制會幫我們自動的把userDaoImpl注入到userServiceImpl中,通過配置autowire可以實現。直接舉個栗子。可以看到我們在配置檔案中刪掉了userDaoImpl,但是Spring一樣會幫我們成功注入。但是要注意的是,如果我們選擇的是byType,那麼對於存在兩個相同Class的userDaoImpl Spring會不知道要注入哪一個,因此會丟擲異常。


   

    autowire-candidate,primary:

    針對上述的問題,Spring提供了兩個方法來解決。第一種如果你在id為userDaoImpl2上面添加了autowire-candidate,那麼就說明如果自動裝配的時候出現衝突,就會忽略當前這個bean即userDaoImpl2。而primary則是反過來,它表示的是一種優先順序,如果遇到衝突情況優先使用帶有該屬性的bean。舉個栗子。

SpringIOC之Annotation註解:

    使用註解的方式的話就不需要在配置檔案中寫這麼多了,相對Ioc而言我認為使用註解更為方便。如果要使用Annotation的方式只需要在配置檔案中新增<context:component-scan base-package="com.ctc" />,那麼你的基本要求就可以實現了,Spring就根據base-package指定的路徑去掃描下面所有的類。我們只需要在業務層資料層上的類新增上註解就可以了。Spring提供了多種註解:@Component,@Service(業務層),@Repository(持久層),@Controller(表現層)。當前我們可以在所以的類上面直接使用@Component一樣可以實現。但是Spring建議你根據需要分開定義,因為在以後的版本中Spring可能會對他們新增一個特性,當前@Repository已經支援了針對異常的新特性。

    @Required:

    如果我們在userServiceImp中在針對userDaoImpl方法上面添加了Required那麼說明你必須顯示的配置檔案中指定這個屬性。否則就會丟擲異常。而Spring的解釋是說,這種情況是為了防止出現NPE。舉個栗子。可以看到,一開始我們沒有配置Required,Spring沒有出現異常這個時候userDaoImpl為空,因此在呼叫addUser的時候出現了NPE。但是如果我們加入了該註解,可以看到這個時候Spring丟擲異常了,說明你必須要在配置檔案配置,否則無法進行下一步。




    @Autowired,@Resource;

    @Autowired跟@Resource都可以作用在構造方法,sette方法,以及屬性值上面注入。它們的區別在於:

  1. Autowired是Spring的規範,而Resource是java的規範;
  2. Autowired預設按型別匹配但是可以搭配@Qualifier來指定名稱,而Resource預設按名稱;

     因為太簡單了,就不提供栗子了~此外xml中提到了屬性在annotation中都可以實現。需要的話自己查文件吧~

Spring在3.X之後使用Java來代替XML配置:

    Spring在3.X之後推薦使用Java 類的方式來代替XML的配置。下面將進行一個簡單的例項。首先建立一個SpringConfig對應一個XML檔案。這邊Configuration表明當前這個類對應一個XML檔案,另外在Junit中我們不再使用ClassPathXMLApplicationContext,而是改用了AnnotationConfigApplicationContext。因為我們不再通過XML的方式來獲取Bean。

@Configuration
@ComponentScan(basePackages="com.ctc")
public class SpringConfig {

}