java-12:spring MVC - 控制反轉IOC,依賴注入DI

學習spring框架之前,先理解幾個概念:

1.第一部分:依賴倒置原則 

2.第二部分:控制反轉,控制反轉容器(實例)

3.第三部分:控制反轉,控制反轉容器(全面理解,面試題)

綜合性理解:控制反轉(IOC)個人理解就是:真正的控制方不是上層類或者下層類,而是框架,也就是控制反轉容器(即中央處理器),由框架根據配置文件提供各下層類實例,通過依賴注入的方式提供給上層類的注入點的接口或者抽象類。

說明:以下三篇文章都是來自知乎,同一個問題的三個回答。地址:https://www.zhihu.com/question/23277575

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

第一部分:依賴倒置原則。個人認爲:僅用此文來理解依賴倒置原則,不要用來理解IOC和DI,否則容易混淆IOC和DI的理解。

文章來自知乎,作者和地址如下。此文系統性說明了依賴倒置原則。個人覺得沒有將IOC和DI說得很透徹。另外,依賴倒置原則一定是依賴接口和抽象,而不是具體的類。所以上層中定義的下層類一定是接口或者抽象父類。

說明1:依賴倒置原則
a.高層模塊不應該依賴於底層模塊,二者都應該依賴於抽象。
b.抽象不應該依賴於細節,細節應該依賴於抽象。

說明2:IoC主要的實現方式有兩種:依賴查找,依賴注入。(128頁)
依賴注入是一種更可取的方式。

--以下是博文:

作者:Mingqi
鏈接:https://www.zhihu.com/question/23277575/answer/169698662
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

要了解控制反轉( Inversion of Control ), 我覺得有必要先了解軟件設計的一個重要思想:依賴倒置原則(Dependency Inversion Principle )

什麼是依賴倒置原則?假設我們設計一輛汽車:先設計輪子,然後根據輪子大小設計底盤,接着根據底盤設計車身,最後根據車身設計好整個汽車。這裏就出現了一個“依賴”關係:汽車依賴車身,車身依賴底盤,底盤依賴輪子。

這樣的設計看起來沒問題,但是可維護性卻很低。假設設計完工之後,上司卻突然說根據市場需求的變動,要我們把車子的輪子設計都改大一碼。這下我們就蛋疼了:因爲我們是根據輪子的尺寸設計的底盤,輪子的尺寸一改,底盤的設計就得修改;同樣因爲我們是根據底盤設計的車身,那麼車身也得改,同理汽車設計也得改——整個設計幾乎都得改!

我們現在換一種思路。我們先設計汽車的大概樣子,然後根據汽車的樣子來設計車身,根據車身來設計底盤,最後根據底盤來設計輪子。這時候,依賴關係就倒置過來了:輪子依賴底盤, 底盤依賴車身, 車身依賴汽車。

這時候,上司再說要改動輪子的設計,我們就只需要改動輪子的設計,而不需要動底盤,車身,汽車的設計了。

這就是依賴倒置原則——把原本的高層建築依賴底層建築“倒置”過來,變成底層建築依賴高層建築。高層建築決定需要什麼,底層去實現這樣的需求,但是高層並不用管底層是怎麼實現的。這樣就不會出現前面的“牽一髮動全身”的情況。

控制反轉(Inversion of Control) 就是依賴倒置原則的一種代碼設計的思路。具體採用的方法就是所謂的依賴注入(Dependency Injection)其實這些概念初次接觸都會感到雲裏霧裏的。說穿了,這幾種概念的關係大概如下:

爲了理解這幾個概念,我們還是用上面汽車的例子。只不過這次換成代碼。我們先定義四個Class,車,車身,底盤,輪胎。然後初始化這輛車,最後跑這輛車。代碼結構如下:

這樣,就相當於上面第一個例子,上層建築依賴下層建築——每一個類的構造函數都直接調用了底層代碼的構造函數。假設我們需要改動一下輪胎(Tire)類,把它的尺寸變成動態的,而不是一直都是30。我們需要這樣改:

由於我們修改了輪胎的定義,爲了讓整個程序正常運行,我們需要做以下改動:

由此我們可以看到,僅僅是爲了修改輪胎的構造函數,這種設計卻需要修改整個上層所有類的構造函數!在軟件工程中,這樣的設計幾乎是不可維護的——在實際工程項目中,有的類可能會是幾千個類的底層,如果每次修改這個類,我們都要修改所有以它作爲依賴的類,那軟件的維護成本就太高了。

所以我們需要進行控制反轉(IoC),及上層控制下層,而不是下層控制着上層。我們用依賴注入(Dependency Injection)這種方式來實現控制反轉。所謂依賴注入,就是把底層類作爲參數傳入上層類,實現上層類對下層類的“控制”。(轉載者:依賴注入是依賴控制反轉容器來對上層對象進行注入。)這裏我們用構造方法傳遞的依賴注入方式重新寫車類的定義:

這裏我們再把輪胎尺寸變成動態的,同樣爲了讓整個系統順利運行,我們需要做如下修改:

看到沒?這裏我只需要修改輪胎類就行了,不用修改其他任何上層類。這顯然是更容易維護的代碼。不僅如此,在實際的工程中,這種設計模式還有利於不同組的協同合作和單元測試:比如開發這四個類的分別是四個不同的組,那麼只要定義好了接口,四個不同的組可以同時進行開發而不相互受限制;而對於單元測試,如果我們要寫Car類的單元測試,就只需要Mock一下Framework類傳入Car就行了,而不用把Framework, Bottom, Tire全部new一遍再來構造Car。

這裏我們是採用的構造函數傳入的方式進行的依賴注入。其實還有另外兩種方法:Setter傳遞接口傳遞。這裏就不多講了,核心思路都是一樣的,都是爲了實現控制反轉

 

看到這裏你應該能理解什麼控制反轉和依賴注入了。那什麼是控制反轉容器(IoC Container)呢?其實上面的例子中,對車類進行初始化的那段代碼發生的地方,就是控制反轉容器。

顯然你也應該觀察到了,因爲採用了依賴注入,在初始化的過程中就不可避免的會寫大量的new。這裏IoC容器就解決了這個問題。這個容器可以自動對你的代碼進行初始化,你只需要維護一個Configuration(可以是xml可以是一段代碼),而不用每次初始化一輛車都要親手去寫那一大段初始化的代碼。這是引入IoC Container的第一個好處。

IoC Container的第二個好處是:我們在創建實例的時候不需要了解其中的細節。在上面的例子中,我們自己手動創建一個車instance時候,是從底層往上層new的:

這個過程中,我們需要了解整個Car/Framework/Bottom/Tire類構造函數是怎麼定義的,才能一步一步new/注入。

而IoC Container在進行這個工作的時候是反過來的,它先從最上層開始往下找依賴關係,到達最底層之後再往上一步一步new(有點像深度優先遍歷):

這裏IoC Container可以直接隱藏具體的創建實例的細節,在我們來看它就像一個工廠:

我們就像是工廠的客戶。我們只需要向工廠請求一個Car實例,然後它就給我們按照Config創建了一個Car實例。我們完全不用管這個Car實例是怎麼一步一步被創建出來。

實際項目中,有的Service Class可能是十年前寫的,有幾百個類作爲它的底層。假設我們新寫的一個API需要實例化這個Service,我們總不可能回頭去搞清楚這幾百個類的構造函數吧?IoC Container的這個特性就很完美的解決了這類問題——因爲這個架構要求你在寫class的時候需要寫相應的Config文件,所以你要初始化很久以前的Service類的時候,前人都已經寫好了Config文件,你直接在需要用的地方注入這個Service就可以了。這大大增加了項目的可維護性且降低了開發難度。

這裏只是很粗略的講了一下我自己對IoC和DI的理解。主要的目的是在於最大限度避免晦澀難懂的專業詞彙,用盡量簡潔,通俗,直觀的例子來解釋這些概念。如果讓大家能有一個類似“哦!原來就是這麼個玩意嘛!”的印象,我覺得就OK了。想要深入瞭解的話,可以上網查閱一些更權威的資料。這裏推薦一下 Dependency injection Inversion of Control Containers and the Dependency Injection pattern 這兩篇文章,講的很好很詳細。

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

第二部分:控制反轉,控制反轉容器

控制反轉(IOC)個人理解就是:真正的控制方不是上層類或者下層類,而是框架,也就是控制反轉容器(即中央處理器),由框架根據配置文件提供各下層類實例,通過依賴注入的方式提供給上層類的注入點的接口或者抽象類。

--以下是博文:

作者:知乎用戶
鏈接:https://www.zhihu.com/question/23277575/answer/24259844
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

 

私以爲以上各位都沒有對spring ioc的精髓講解到位。大多都在很模糊的說是什麼,抽象化的表述或者含糊其辭的說概念。

ioc的思想最核心的地方在於,資源不由使用資源的雙方管理,而由不使用資源的第三方管理(轉載者:比如框架),這可以帶來很多好處。第一,資源集中管理,實現資源的可配置和易管理。第二,降低了使用資源雙方的依賴程度,也就是我們說的耦合度。

也就是說,甲方要達成某種目的不需要直接依賴乙方,它只需要達到的目的告訴第三方機構就可以了,比如甲方需要一雙襪子,而乙方它賣一雙襪子,它要把襪子賣出去,並不需要自己去直接找到一個賣家來完成襪子的賣出。它也只需要找第三方,告訴別人我要賣一雙襪子。這下好了,甲乙雙方進行交易活動,都不需要自己直接去找賣家,相當於程序內部開放接口,賣家由第三方作爲參數傳入。甲乙互相不依賴,而且只有在進行交易活動的時候,甲才和乙產生聯繫。反之亦然。這樣做什麼好處麼呢,甲乙可以在對方不真實存在的情況下獨立存在,而且保證不交易時候無聯繫,想交易的時候可以很容易的產生聯繫。甲乙交易活動不需要雙方見面,避免了雙方的互不信任造成交易失敗的問題。因爲交易由第三方來負責聯繫,而且甲乙都認爲第三方可靠。那麼交易就能很可靠很靈活的產生和進行了。

這就是ioc的核心思想。生活中這種例子比比皆是,支付寶在整個淘寶體系裏就是龐大的ioc容器,交易雙方之外的第三方,提供可靠性可依賴可靈活變更交易方的資源管理中心。另外人事代理也是,僱傭機構和個人之外的第三方。嗯,就這樣,希望對題主有幫助。

==update=== 
在以上的描述中,誕生了兩個專業詞彙,依賴注入和控制反轉
所謂的依賴注入,則是,甲方開放接口,在它需要的時候,能夠講乙方傳遞進來(注入)
所謂的控制反轉,甲乙雙方不相互依賴,交易活動的進行不依賴於甲乙任何一方,整個活動的進行由第三方負責管理。

這就是spring IOC的思想所在,不要只談DI IOC這些概念。

人之所惡在好爲人師,不實知,謹慎言。

 

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

3.第三部分:控制反轉,控制反轉容器。一個全面的理解,一針見血。還有亮點是包含面試題。

作者:Java3y
鏈接:https://www.zhihu.com/question/23277575/answer/680699595
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

 

在刷Spring書籍的時候花了點時間去學習了單例模式和工廠模式,總的來說還是非常值得的!

本來想的是刷完《Spring 實戰 (第4版)》和《精通Spring4.x 企業應用開發實戰》的IOC章節後來重新編寫一篇IOC的文章的,看了一下之前已經寫過的入門系列Spring入門這一篇就夠了Spring【依賴注入】就是這麼簡單。最主要的知識點都已經講過了,所以感覺就沒必要重新來編寫這些知識點了...

我個人又不喜歡將寫過的東西複製到新的文章中,所以建議大家可以先去閱讀上面兩篇文章再來看這篇(工廠模式那篇如果沒有看過的同學也有必要去看看)~~

  • 爲了這篇文章知識點的完整性,重要的知識點(IOC概念理解,創建Bean、注入的三種方式等)還是會出現,但是不會將上面兩篇博文的代碼摘抄過來了。

這篇文章主要是補充和強化一些比較重要的知識點,並會把上面的兩本書關於IOC的知識點整理出來並畫成一個思維導圖來全面瞭解Spring IOC的知識點!

那麼接下來就開始吧,如果有錯的地方希望能多多包涵,並不吝在評論區指正!

一、Spring IOC全面認知

結合《Spring 實戰 (第4版)》和《精通Spring4.x 企業應用開發實戰》兩本書的IOC章節將其知識點整理起來~

1.1IOC和DI概述

在《精通Spring4.x 企業應用開發實戰》中對IOC的定義是這樣的:

IoC(Inversion of Control)控制反轉,包含了兩個方面:一、控制。二、反轉

我們可以簡單認爲:

  • 控制指的是:當前對象對內部成員的控制權
  • 反轉指的是:這種控制權不由當前對象管理了,由其他(類,第三方容器)來管理。
IOC不夠開門見山,於是Martin Fowler提出了DI(dependency injection)來替代IoC,即讓調用類對某一接口實現類的依賴關係由第三方(容器或協作類)注入,以移除調用類對某一接口實現類的依賴。

在《Spring 實戰 (第4版)》中並沒有提及到IOC,而是直接來說DI的:

通過DI,對象的依賴關係將由系統中負責協調各對象的第三方組件在創建對象的時候進行設定,對象無需自行創建或管理它們的依賴關係,依賴關係將被自動注入到需要它們的對象當中去

從書上我們也可以發現:IoC和DI的定義(區別)並不是如此容易就可以說得清楚的了。這裏我就簡單摘抄一下:

  • IoC(思想,設計模式)主要的實現方式有兩種:依賴查找,依賴注入
  • 依賴注入是一種更可取的方式(實現的方式)

對我們而言,其實也沒必要分得那麼清,混合一談也不影響我們的理解...

再通過昨天寫過的工廠模式理解了沒有?,我們現在就可以很清楚的發現,其實所謂的IOC容器就是一個大工廠【第三方容器】(Spring實現的功能很強大!比我們自己手寫的工廠要好很多)。

使用IOC的好處(知乎@Intopass的回答):

  1. 不用自己組裝,拿來就用。
  2. 享受單例的好處,效率高,不浪費空間。
  3. 便於單元測試,方便切換mock組件。
  4. 便於進行AOP操作,對於使用者是透明的。
  5. 統一配置,便於修改。

參考資料:

1.2IOC容器的原理

從上面就已經說了:IOC容器其實就是一個大工廠,它用來管理我們所有的對象以及依賴關係。

  • 原理就是通過Java的反射技術來實現的!通過反射我們可以獲取類的所有信息(成員變量、類名等等等)!
  • 再通過配置文件(xml)或者註解來描述類與類之間的關係
  • 我們就可以通過這些配置信息和反射技術來構建出對應的對象和依賴關係了!

上面描述的技術只要學過點Java的都能說出來,這一下子可能就會被面試官問倒了,我們簡單來看看實際Spring IOC容器是怎麼實現對象的創建和依賴的:

 

 

  1. 根據Bean配置信息在容器內部創建Bean定義註冊表
  2. 根據註冊表加載、實例化bean、建立Bean與Bean之間的依賴關係
  3. 將這些準備就緒的Bean放到Map緩存池中,等待應用程序調用

Spring容器(Bean工廠)可簡單分成兩種:

  • BeanFactory
    • 這是最基礎、面向Spring的
  • ApplicationContext
    • 這是在BeanFactory基礎之上,面向使用Spring框架的開發者。提供了一系列的功能!

 

幾乎所有的應用場合都是使用ApplicationContext!

BeanFactory的繼承體系:

 

 

ApplicationContext的繼承體系:

 

 

其中在ApplicationContext子類中又有一個比較重要的:WebApplicationContext

  • 專門爲Web應用準備的

 

 

Web應用與Spring融合:

 

 

我們看看BeanFactory的生命週期:

 

 

接下來我們再看看ApplicationContext的生命週期:

 

 

初始化的過程都是比較長,我們可以分類來對其進行解析:

  • Bean自身的方法:如調用 Bean 構造函數實例化 Bean,調用 Setter 設置 Bean 的屬性值以及通過的 init-method 和 destroy-method 所指定的方法;
  • Bean級生命週期接口方法:如 BeanNameAware、 BeanFactoryAware、 InitializingBean 和 DisposableBean,這些接口方法由 Bean 類直接實現;
  • 容器級生命週期接口方法:在上圖中帶“★” 的步驟是由 InstantiationAwareBean PostProcessor 和 BeanPostProcessor 這兩個接口實現,一般稱它們的實現類爲“ 後處理器” 。 後處理器接口一般不由 Bean 本身實現,它們獨立於 Bean,實現類以容器附加裝置的形式註冊到Spring容器中並通過接口反射爲Spring容器預先識別。當Spring 容器創建任何 Bean 的時候,這些後處理器都會發生作用,所以這些後處理器的影響是全局性的。當然,用戶可以通過合理地編寫後處理器,讓其僅對感興趣Bean 進行加工處理

ApplicationContext和BeanFactory不同之處在於:

  • ApplicationContext會利用Java反射機制自動識別出配置文件中定義的BeanPostProcessor、 InstantiationAwareBeanPostProcesso 和BeanFactoryPostProcessor後置器,並自動將它們註冊到應用上下文中。而BeanFactory需要在代碼中通過手工調用addBeanPostProcessor()方法進行註冊
  • ApplicationContext在初始化應用上下文的時候就實例化所有單實例的Bean。而BeanFactory在初始化容器的時候並未實例化Bean,直到第一次訪問某個Bean時實例化目標Bean。

有了上面的知識點了,我們再來詳細地看看Bean的初始化過程:

 

 

簡要總結:

  • BeanDefinitionReader讀取Resource所指向的配置文件資源,然後解析配置文件。配置文件中每一個<bean>解析成一個BeanDefinition對象,並保存到BeanDefinitionRegistry中;
  • 容器掃描BeanDefinitionRegistry中的BeanDefinition;調用InstantiationStrategy進行Bean實例化的工作;使用BeanWrapper完成Bean屬性的設置工作;
  • 單例Bean緩存池:Spring 在DefaultSingletonBeanRegistry類中提供了一個用於緩存單實例 Bean 的緩存器,它是一個用HashMap實現的緩存器,單實例的Bean以beanName爲鍵保存在這個HashMap中。

1.3IOC容器裝配Bean

1.3.1裝配Bean方式

Spring4.x開始IOC容器裝配Bean有4種方式:

  • XML配置
  • 註解
  • JavaConfig
  • 基於Groovy DSL配置(這種很少見)

總的來說:我們以XML配置+註解來裝配Bean得多,其中註解這種方式佔大部分

1.3.2依賴注入方式

依賴注入的方式有3種方式:

  • 屬性注入-->通過setter()方法注入
  • 構造函數注入
  • 工廠方法注入

總的來說使用屬性注入是比較靈活和方便的,這是大多數人的選擇!

1.3.3對象之間關係

<bean>對象之間有三種關係:

  • 依賴-->挺少用的(使用depends-on就是依賴關係了-->前置依賴【依賴的Bean需要初始化之後,當前Bean纔會初始化】)
  • 繼承-->可能會用到(指定abstract和parent來實現繼承關係)
  • 引用-->最常見(使用ref就是引用關係了)

1.3.4Bean的作用域

Bean的作用域:

  • 單例Singleton
  • 多例prototype
  • 與Web應用環境相關的Bean作用域
    • reqeust
    • session

使用到了Web應用環境相關的Bean作用域的話,是需要我們手動配置代理的~

 

 

原因也很簡單:因爲我們默認的Bean是單例的,爲了適配Web應用環境相關的Bean作用域--->每個request都需要一個對象,此時我們返回一個代理對象出去就可以完成我們的需求了!

 

 

將Bean配置單例的時候還有一個問題:

  • 如果我們的Bean配置的是單例,而Bean對象裏邊的成員對象我們希望是多例的話。那怎麼辦呢??
  • 默認的情況下我們的Bean單例,返回的成員對象也默認是單例的(因爲對象就只有那麼一個)!

此時我們需要用到了lookup方法注入,使用也很簡單,看看例子就明白了:

 

 

 

1.3.6處理自動裝配的歧義性

昨天在刷書的時候剛好看到了有人在知乎邀請我回答這個問題:

 

結合兩本書的知識點,可以歸納成兩種解決方案:

  • 使用@Primary註解設置爲首選的注入Bean
  • 使用@Qualifier註解設置特定名稱的Bean來限定注入!
    • 也可以使用自定義的註解來標識

 

1.3.7引用屬性文件以及Bean屬性

之前在寫配置文件的時候都是直接將我們的數據庫配置信息在裏面寫死的了:

 

其實我們有更優雅的做法:將這些配置信息寫到配置文件上(因爲這些配置信息很可能是會變的,而且有可能被多個配置文件引用).

  • 如此一來,我們改的時候就十分方便了。

 

引用配置文件的數據使用的是${}

除了引用配置文件上的數據,我們還可以引用Bean的屬性

 

 

 

 

引用Bean的屬性使用的是#{}

在這種技術在《Spring 實戰 第四版》稱之爲Spring EL,跟我們之前學過的EL表達式是類似的。主要的功能就是上面的那種,想要更深入瞭解可參考下面的鏈接:

1.3.8組合配置文件

xml文件之間組合:

 

 

xml和javaconfig互相組合的方式:

public static void main(String[] args) {
		
        //1.通過構造函數加載配置類
         ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConf.class);

        //2.通過編碼方式註冊配置類
		 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
		 ctx.register(DaoConfig.class);
		 ctx.register(ServiceConfig.class);
		 ctx.refresh();

        //3.通過XML組裝@Configuration配置類所提供的配置信息
		 ApplicationContext ctx = new ClassPathXmlApplicationContext("com/smart/conf/beans2.xml");

        //4.通過@Configuration組裝XML配置所提供的配置信息
		 ApplicationContext ctx = new AnnotationConfigApplicationContext(LogonAppConfig.class);

		 //5.@Configuration的配置類相互引用
		 ApplicationContext ctx = new AnnotationConfigApplicationContext(DaoConfig.class,ServiceConfig.class);
         LogonService logonService = ctx.getBean(LogonService.class);
         System.out.println((logonService.getLogDao() !=null));
         logonService.printHelllo();   
	}

第一種的例子:

 

 

第二種的例子:

 

 

 

 

第三種的例子:

 

 

第四種的例子:

 

 

第五種的例子:

  • 代碼由上可見

1.3.9裝配Bean總結

總的來說,Spring IOC容器就是在創建Bean的時候有很多的方式給了我們實現,其中也包括了很多關於Bean的配置~

對於Bean相關的注入教程代碼和簡化配置(p和c名稱空間)我就不一一說明啦,你們去看Spring入門這一篇就夠了Spring【依賴注入】就是這麼簡單就行了。

總的對比圖:

 

 

分別的應用場景:

 

 

至於一些小的知識點:

  • 方法替換
    • 使用某個Bean的方法替換成另一個Bean的方法
  • 屬性編輯器
    • Spring可以對基本類型做轉換就歸結於屬性編輯器的功勞!
  • 國際化
    • 使用不同語言(英語、中文)的操作系統去顯式不同的語言
  • profile與條件化的Bean
    • 滿足了某個條件才初始化Bean,這可以方便切換生產環境和開發環境~
  • 容器事件
    • 類似於我們的Servlet的監聽器,只不過它是在Spring中實現了~

 

上面這些小知識點比較少情況會用到,這也不去講解啦。知道有這麼一回事,到時候查查就會用啦~~~

二、Spring IOC相關面試題

將SpringIOC相關知識點整理了一遍,要想知道哪些知識點是比較重要的。很簡單,我們去找找相關的面試題就知道了,如果該面試題是常見的,那麼說明這個知識點還是相對比較重要的啦!

以下的面試題從各種博客上摘抄下來,摘抄量較大的會註明出處的~

2.1什麼是spring?

什麼是spring?

Spring 是個java企業級應用的開源開發框架。Spring主要用來開發Java應用,但是有些擴展是針對構建J2EE平臺的web應用。Spring框架目標是簡化Java企業級應用開發,並通過POJO爲基礎的編程模型促進良好的編程習慣。

2.2使用Spring框架的好處是什麼?

使用Spring框架的好處是什麼?
  • 輕量:Spring 是輕量的,基本的版本大約2MB。
  • 控制反轉:Spring通過控制反轉實現了鬆散耦合,對象們給出它們的依賴,而不是創建或查找依賴的對象們。
  • 面向切面的編程(AOP):Spring支持面向切面的編程,並且把應用業務邏輯和系統服務分開。
  • 容器:Spring 包含並管理應用中對象的生命週期和配置。
  • MVC框架:Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品。
  • 事務管理:Spring 提供一個持續的事務管理接口,可以擴展到上至本地事務下至全局事務(JTA)。
  • 異常處理:Spring 提供方便的API把具體技術相關的異常(比如由JDBC,Hibernate or JDO拋出的)轉化爲一致的unchecked 異常。

2.3Spring由哪些模塊組成?

Spring由哪些模塊組成?

簡單可以分成6大模塊:

  • Core
  • AOP
  • ORM
  • DAO
  • Web
  • Spring EE

 

 

2.4BeanFactory 實現舉例

BeanFactory 實現舉例

Bean工廠是工廠模式的一個實現,提供了控制反轉功能,用來把應用的配置和依賴從正真的應用代碼中分離

在spring3.2之前最常用的是XmlBeanFactory的,但現在被廢棄了,取而代之的是:XmlBeanDefinitionReader和DefaultListableBeanFactory

2.5什麼是Spring的依賴注入?

什麼是Spring的依賴注入?

依賴注入,是IOC的一個方面,是個通常的概念,它有多種解釋。這概念是說你不用創建對象,而只需要描述它如何被創建。你不在代碼裏直接組裝你的組件和服務,但是要在配置文件裏描述哪些組件需要哪些服務,之後一個容器(IOC容器)負責把他們組裝起來。

2.6有哪些不同類型的IOC(依賴注入)方式?

有哪些不同類型的IOC(依賴注入)方式?
  • 構造器依賴注入:構造器依賴注入通過容器觸發一個類的構造器來實現的,該類有一系列參數,每個參數代表一個對其他類的依賴。
  • Setter方法注入:Setter方法注入是容器通過調用無參構造器或無參static工廠 方法實例化bean之後,調用該bean的setter方法,即實現了基於setter的依賴注入。
  • 工廠注入:這個是遺留下來的,很少用的了!

2.7哪種依賴注入方式你建議使用,構造器注入,還是 Setter方法注入?

哪種依賴注入方式你建議使用,構造器注入,還是 Setter方法注入?

你兩種依賴方式都可以使用,構造器注入和Setter方法注入。最好的解決方案是用構造器參數實現強制依賴,setter方法實現可選依賴

2.8什麼是Spring beans?

什麼是Spring beans?

Spring beans 是那些形成Spring應用的主幹的java對象。它們被Spring IOC容器初始化,裝配,和管理。這些beans通過容器中配置的元數據創建。比如,以XML文件中<bean/>的形式定義。

這裏有四種重要的方法給Spring容器提供配置元數據

  • XML配置文件。
  • 基於註解的配置。
  • 基於java的配置。
  • Groovy DSL配置

2.9解釋Spring框架中bean的生命週期

解釋Spring框架中bean的生命週期
  • Spring容器 從XML 文件中讀取bean的定義,並實例化bean。
  • Spring根據bean的定義填充所有的屬性。
  • 如果bean實現了BeanNameAware 接口,Spring 傳遞bean 的ID 到 setBeanName方法。
  • 如果Bean 實現了 BeanFactoryAware 接口, Spring傳遞beanfactory 給setBeanFactory 方法。
  • 如果有任何與bean相關聯的BeanPostProcessors,Spring會在postProcesserBeforeInitialization()方法內調用它們。
  • 如果bean實現IntializingBean了,調用它的afterPropertySet方法,如果bean聲明瞭初始化方法,調用此初始化方法。
  • 如果有BeanPostProcessors 和bean 關聯,這些bean的postProcessAfterInitialization() 方法將被調用。
  • 如果bean實現了 DisposableBean,它將調用destroy()方法。

2.10解釋不同方式的自動裝配

解釋不同方式的自動裝配
  • no:默認的方式是不進行自動裝配,通過顯式設置ref 屬性來進行裝配。
  • byName:通過參數名 自動裝配,Spring容器在配置文件中發現bean的autowire屬性被設置成byname,之後容器試圖匹配、裝配和該bean的屬性具有相同名字的bean。
  • byType::通過參數類型自動裝配,Spring容器在配置文件中發現bean的autowire屬性被設置成byType,之後容器試圖匹配、裝配和該bean的屬性具有相同類型的bean。如果有多個bean符合條件,則拋出錯誤。
  • constructor:這個方式類似於byType, 但是要提供給構造器參數,如果沒有確定的帶參數的構造器參數類型,將會拋出異常。
  • autodetect:首先嚐試使用constructor來自動裝配,如果無法工作,則使用byType方式。

只用註解的方式時,註解默認是使用byType的

2.11IOC的優點是什麼?

IOC的優點是什麼?

IOC 或 依賴注入把應用的代碼量降到最低。它使應用容易測試,單元測試不再需要單例和JNDI查找機制。最小的代價和最小的侵入性使鬆散耦合得以實現。IOC容器支持加載服務時的餓漢式初始化和懶加載

2.12哪些是重要的bean生命週期方法? 你能重載它們嗎?

哪些是重要的bean生命週期方法? 你能重載它們嗎?

有兩個重要的bean 生命週期方法,第一個是setup, 它是在容器加載bean的時候被調用。第二個方法是 teardown它是在容器卸載類的時候被調用。

The bean 標籤有兩個重要的屬性(init-methoddestroy-method)。用它們你可以自己定製初始化和註銷方法。它們也有相應的註解(@PostConstruct@PreDestroy)。

2.13怎麼回答面試官:你對Spring的理解?

怎麼回答面試官:你對Spring的理解?

來源:

下面我就截幾個答案:

一、

 

 

二、

 

 

2.14Spring框架中的單例Beans是線程安全的麼?

Spring框架中的單例Beans是線程安全的麼?

Spring框架並沒有對單例bean進行任何多線程的封裝處理。關於單例bean的線程安全和併發問題需要開發者自行去搞定。但實際上,大部分的Spring bean並沒有可變的狀態(比如Serview類和DAO類),所以在某種程度上說Spring的單例bean是線程安全的。如果你的bean有多種狀態的話(比如 View Model 對象),就需要自行保證線程安全

最淺顯的解決辦法就是將多態bean的作用域由“singleton”變更爲“prototype”

2.15FileSystemResource和ClassPathResource有何區別?

FileSystemResource和ClassPathResource有何區別?

在FileSystemResource 中需要給出spring-config.xml文件在你項目中的相對路徑或者絕對路徑。在ClassPathResource中spring會在ClassPath中自動搜尋配置文件,所以要把ClassPathResource文件放在ClassPath下。

如果將spring-config.xml保存在了src文件夾下的話,只需給出配置文件的名稱即可,因爲src文件夾是默認。

簡而言之,ClassPathResource在環境變量中讀取配置文件,FileSystemResource在配置文件中讀取配置文件

三、總結

這篇文章的主要知識點我畫了一張思維導圖來總結啦,當學習到AOP的時候,這張思維導圖會繼續補充的哦~~~

 

http://weixin.qq.com/r/uDgqMjPEOW5GrXdR922q123 (二維碼自動識別)

 

參考資料:

文章首發公衆號:Java3y 號內有海量的視頻資源和原創的思維導圖,關注即可獲取!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章