當前位置:
首頁 > 知識 > 如何用比較快速的方法掌握Spring的核心!

如何用比較快速的方法掌握Spring的核心!

Java方面的高級程序員一定得掌握Spring的技能,其中包括Spring 依賴注入(IOC),面向切面(AOP),和資料庫的整合(比如和Hibernate整合或聲明式事務等)以及Spring MVC架構。其中,Spring的依賴注入是重中之重,在面試時,面試官一定會問這方面的問題。

根據我的培訓和面試經驗,這方面的知識點雖然不難(初學者估計最多3天就能看明白並調通程序),但要把其中的各混淆點(也就是面試點)講清楚不容易,換句話說,初級程序員在學習Spring IOC這部分的知識時,或多或少會走些彎路,在通常情況下,會經過一次或多次面試的失敗(就是交學費)後才能理順這部分的知識體系。

在本文里,將整理歸納 java web輕量級開發面試教程 里的相關知識點,一次性地把這部分的知識點講全,可以這樣說,大家看完這篇文章後,能盡量減少交學費的次數。

以上是開場白,如下是正文。

--------------------------------------------------------------------------------------------------------------------

1 通過一個簡單但易學的案例來了解依賴注入

步驟一 開發提供服務的SayHello.java程序。

1 package com; 2 public class SayHello { 3 private HelloWorldSpring helloWorldSpring; 4 public HelloWorldSpring getHelloWorldSpring() { 5 return helloWorldSpring; 6 } 7 public void setHelloWorldSpring(HelloWorldSpring helloWorldSpring) { 8 this.helloWorldSpring = helloWorldSpring; 9 } 10 public void sayHello(){ 11 System.out.println("Say Hello:" + helloWorldSpring.sayHello()); 12 } 13 }

第10行定義了一個sayHello的方法,在這方法里,調用了在第3行定義的helloWorldSpring對象,輸出一串文字。

這裡有一個比較有意思的現象,雖然在第4行和第7行針對helloWorldSpring對象定義了get和set的方法,但在第11行使用helloWorldSpring對象之前,始終沒有用new關鍵字初始化這個對象,那麼按照以往的經驗,會不會出現空指針異常呢?

別著急,先看下HelloWorldSpring這個類里有沒有特殊的動作。

步驟二 定義HelloWorldSpring.java這個類。

1 package com; 2 public class HelloWorldSpring { 3 private String sayContent; 4 public String sayHello() { 5 System.out.println("HelloWorld Spring!"); 6 return "Hello World Spring"; 7 } 8 }

這裡直接在第4行定義了sayHello的方法,也沒看到特殊的代碼。接下來看一下在SpringMain這個類里是如何調用的。

步驟三 開發調用者SpringMain.java,請大家注意一下調用sayHello方法的方式。

1 package com; 2 import org.springframework.context.ApplicationContext; 3 import org.springframework.context.support.ClassPathXmlApplicationContext; 4 public class SpringMain { 5 public static void main(String[] args) { 6 ApplicationContext context = new ClassPathXmlApplicationContext( 7 "conf/applicationContext-*.xml"); 8 9 SayHello sayHello = (SayHello) context.getBean("SayHello"); 10 sayHello.sayHello(); 11 } 12 }

關鍵代碼在第9行和第10行,是通過一個getBean方法,獲得了SayHello對象的一個實例,隨後調用了其中的sayHello方法。在這之前,通過第6行的代碼,裝載了一個配置文件。

戲法變到這裡,大家看到了兩個不可思議的地方。第一,在SayHello類里,始終沒有初始化HelloWorldSpring對象,就直接用了。第二,在SpringMain類里,沒有像往常那樣用SayHello sayHello = new SayHello(); 的方法初始化對象,而是通過getBean的方式來獲得類的實例。

其實,這裡大家已經能看到「低耦合」的寫法了。讓我們最後看完Spring的配置文件再來綜合體驗IoC的好處。

步驟四 編寫Spring的配置文件applicationContext-service-api.xml,關鍵代碼如下

1 <bean id="HelloWorldSpring" class="com.HelloWorldSpring"> 2 </bean> 3 <bean id="SayHello" class="com.SayHello" > 4 <property name="helloWorldSpring" ref="HelloWorldSpring" /> 5 </bean>

在第1行和第2行里,定義了一個Bean。在Spring里,一個Bean往往和一個類所對應,這裡id是HelloWorldSpring的這個Bean是和com.HelloWorldSpring這個類所對應。

而在第3行到第5行里,用id是SayHello這個Bean對應com.SayHello這個類,請大家注意第4行,用內置property這個方式,把HelloWorldSpring這個類內嵌到SayHello類里。

2 IoC的特點,不用New就可以初始化類

SpringMain.java的主要代碼如下。

1 ApplicationContext context = new ClassPathXmlApplicationContext("conf/applicationContext-*.xml")

2 SayHello sayHello = (SayHello) context.getBean("SayHello")

3 sayHello.sayHello()

運行SpringMain.java時,首先是把配置文件里定義的信息裝載到context類里;接著在第2行里,通過context.getBean方法,根據配置文件的定義,獲取ID為SayHello(即class是com.SayHello)這個類;隨後在第3行里使用這個類的sayHello方法。從代碼中大家可以看出,這裡同樣沒有用到new,而是根據配置文件來初始化類。

沒有使用new,就意味著低耦合,具體而言,就是SayHello、HelloWorldSpring和SpringMain這三個類之間的耦合度很低。

假設有三個團隊在開發維護這三個類,如果用常規new方法來創建類,比如在SayHello類里用HelloWorldSpring helloWorldSpring = new HelloWOrldSpring();,那麼一旦管理HelloWorldSpring類的團隊要修改調用的介面,比如new的構造函數需要帶參數,那麼SayHello類的管理者就不得不受無妄之災,也需要修改本身的代碼。

要知道在公司里,修改代碼並且發布到生產環境,要經過很煩瑣且很嚴格的審批流程,必須要經歷代碼審查、代碼提交、測試人員測試、領導審批、最終發布以及發布後檢查這些步驟。如果用剛才看到的通過配置文件裝載類,在本地代碼里沒有new的這套開發方式,那麼如果一個團隊修改了代碼,其他團隊就有可能不必改動代碼,這樣就可以很大程度上避免不必要的工作。

3 控制翻轉和依賴注入

控制翻轉的英文名字叫IoC(Inversion of Control),依賴注入英文名叫DI(Dependency Injection),下面通過下表來看一下它們的概念。


概念名 含義 表現形式
控制翻轉(IoC,控制反轉) 類之間的關係,不用代碼控制,而是由Spring容器(也就是Spring的jar包)來控制。控制權由代碼翻轉到容器里,這叫控制翻轉 在初始化對象時,在代碼里無須new,而是把類之間的關係寫到配置文件里
依賴注入(DI) 在代碼運行時,如果我們要在一個類里使用(也叫注入)另一個類,比如在上述的SayHello類里要初始化另外一個HelloWorldSpring類,那麼這種注入就是依賴於配置文件的 同樣是把類之間的調用關係寫到配置文件里,在運行時,會根據配置文件,把HelloWorldSpring這個類注入SayHello里

概念名

含義

表現形式

控制翻轉(IoC,控制反轉)

類之間的關係,不用代碼控制,而是由Spring容器(也就是Spring的jar包)來控制。控制權由代碼翻轉到容器里,這叫控制翻轉

在初始化對象時,在代碼里無須new,而是把類之間的關係寫到配置文件里

依賴注入(DI)

在代碼運行時,如果我們要在一個類里使用(也叫注入)另一個類,比如在上述的SayHello類里要初始化另外一個HelloWorldSpring類,那麼這種注入就是依賴於配置文件的

同樣是把類之間的調用關係寫到配置文件里,在運行時,會根據配置文件,把HelloWorldSpring這個類注入SayHello里

通過上面的描述,能看到它們其實是從不同的角度講述的同一件事情。依賴注入強調類的注入是由Spring容器在運行時完成,而控制反轉強調類之間的關係是由Spring容器控制。

從這兩個名詞可知, Spring給我們帶來了一種全新的編程理念,即不用new也可以創建和使用對象。這種開發方式讓我們能像搭積木一樣組裝不同的類,組裝後的類之間的耦合度很低,一個類的修改可以不影響(或者影響度很小)其他的類,這樣就可以避免一個小修改帶來的一大串連鎖反應。

大家在了解Spring的時候,一定請理解「低耦合」這個好處,這本來是面向對象思想帶給我們的好處,在Spring開發的過程中我們確實能感受到。

4 讀取配置文件的各種方式

在Spring里,通常在配置文件中描述各類以及類之間的包含關係,在使用的時候,會先載入配置文件,Spring的內核會讀取配置文件,隨後動態地組裝各類。

通過下表來總結一下讀取配置文件的各種方式,它們之間沒有優劣之分,大家可以挑選個最適用的,具體來講,沒有特殊情況,就可以用ClassPathXmlApplicationContext。


類名 例子
XmlBeanFactory Resource resource = new ClassPathResource("bean.xml"); BeanFactory factory = new XmlBeanFactory(resource)
ClassPathXmlApplicationContext ApplicationContext factory=new ClassPathXmlApplicationContext("conf/appcontext.xml")
用文件系統類來讀取 FileSystemXmlApplicationContext ApplicationContext factory=new FileSystemXmlApplicationContext("classpath:appcontext.xml")

類名

例子

XmlBeanFactory

Resource resource = new ClassPathResource("bean.xml")

BeanFactory factory = new XmlBeanFactory(resource)

ClassPathXmlApplicationContext

ApplicationContext factory=new ClassPathXmlApplicationContext("conf/appcontext.xml")

用文件系統類來讀取

FileSystemXmlApplicationContext

ApplicationContext factory=new FileSystemXmlApplicationContext("classpath:appcontext.xml")

5 單例和多例

我們知道,Spring的容器會在程序運行時,根據配置文件自動地創建(或者叫實例化)具體的Java類(也叫class,或叫Bean)。在配置文件里,可以設置創建文件時是否用單例的方式,如果沒有設置,則會自動用默認的單例的方式來創建文件。如果不想用單例,則可以通過如下兩種語法來修改,它們是等價的。

<bean id="SayHello" class="com.SayHello" singleton="false"> 或者

<bean id="SayHello" class="com.SayHello" scope="prototype">

在實際項目中,一般用單例模式來創建無狀態的Bean,而對於有狀態的Bean,一般不用這種模式。所謂無狀態的Bean,是指沒有能夠標識它目前狀態屬性的Bean,比如共享單車,A用好以後,可以放入共享池(即放到馬路邊上),B可以繼續使用。由於沒有供某個特定的用戶使用,所以也就不能保持某一用戶的狀態,所以叫無狀態Bean。相反,如果針對個人的自行車,那麼會有個狀態來表明是個人的。

講到這裡,請大家確認如下概念,並不是我們首先設置了singleton是false,所以Spring容器才用單例的方式,恰恰相反,根據實際的需求,待創建的類可以被其他多個類共享,因此我們才設置singleton是false。是先有需求再有具體的實現。

這個知識點可以說是Spring面試的必考點,下面通過下表來對比一下兩者的差別


列別 實際用例 特點
有狀態Bea 我們訪問網站登錄後都有自己的用戶名和密碼,系統可以用一個有狀態的Bean來記錄我們的訪問信息,比如來源IP訪問頁面列表和訪問時間等 會為每次調用創建一個實例,一旦調用結束,比如用戶離開了網站,則該Bean就會被銷毀
無狀態Bea 資料庫連接的通用類,其他類可以用它來獲取資料庫連接並進行操作 可以在緩衝池裡只維護一個實例,無須創建和銷毀操作,性能高,但是線程不安全

列別

實際用例

特點

有狀態Bea

我們訪問網站登錄後都有自己的用戶名和密碼,系統可以用一個有狀態的Bean來記錄我們的訪問信息,比如來源IP訪問頁面列表和訪問時間等

會為每次調用創建一個實例,一旦調用結束,比如用戶離開了網站,則該Bean就會被銷毀

無狀態Bea

資料庫連接的通用類,其他類可以用它來獲取資料庫連接並進行操作

可以在緩衝池裡只維護一個實例,無須創建和銷毀操作,性能高,但是線程不安全

6 論面試

當年我追過一本小說,叫天擇,裡面有個故事情節,皇帝請主角吃飯,讓主角點菜,主角點的不是龍肝鳳膽,也不是山珍海味,是兩個家常菜,炒青菜和蛋炒飯,如下我引用的是書中原話:

天下萬事萬物,都是有一個從簡單到複雜,又從複雜趨向於簡單的過程,用道家的話來說,就是天下大道,以簡馭繁,用佛家的話來說,就是看山是山,看山不是山,看山仍是山的三大境界。蛋炒飯和炒青菜這兩樣東西每個人都吃了不知道多少次,但是,正因為如此,能夠在這平凡當中做出來令人難忘的偉大味道,這才是頂尖的高手的境界!

學習Spring IOC這平凡的知識點,也會經歷過上述」從簡單到複雜「的過程,作者根據多年面試培訓(甚至包括寫書)的經驗,從紛繁複雜的Spring IOC的諸多知識點中提煉出針對初級程序員有用的上述內容,不能說是頂尖高手,但至少也經過沉澱,對大家多少有些幫助,也一定能幫助大家少走些彎路(這也是本文申請加入首頁的理由)。

面試時也這樣,面試官會在乎候選人掌握多少知識點(廣度),更在乎對於知識點的深度,如果候選人能從IOC這種平凡的知識點裡說出自己的高深體會,這樣反而能更打動面試官。

在這方面可以說出如下的要點:

1 基本概念(誰都會說)

2 結合項目說明怎麼用IOC,以及IOC的好處(不用new就能用,低耦合),這大家可以結合本文里提到的案例說明

3 一些外圍的知識點,比如如何導入配置文件

4 特別地,請講述單例和多例,並請結合具體例子說明在項目里的用法。

文章摘自博客園


中公優就業 幫你成就職業夢:

IT教育專業培訓:https://www.ujiuye.com/

IT職業在線教育:https://xue.ujiuye.com/

大數據時代下做java開發工程師:https://www.ujiuye.com/zt/java/?wt.bd=lsh11tt

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT優就業 的精彩文章:

你們身旁有哪些學霸的傳奇故事?
重磅!社會化媒體電商新人如何紅海逆襲?
深入理解計算機系統——操作系統的抽象概念
MySQL的JOIN——優化實踐之內循環的次數
你之所以不優秀,是因為你只走容易的路

TAG:IT優就業 |