Spring面試總結(全)

1、Spring 是什麼?

Spring 是一個輕量級的 IoC 和 AOP 容器框架。是爲 Java 應用程序提供基礎性服務的一套框架,目的是用於簡化企業應用程序的開發,它使得開發者只需要關心業務需求。常見的配置方式有三種:基於 XML 的配置、基於註解的配置、基於 Java 的配置。

主要由以下幾個模塊組成:

  • Spring Core:核心類庫,提供 IOC 服務;

  • Spring Context:提供框架式的 Bean 訪問方式,以及企業級功能(JNDI、定時任務等);

  • Spring AOP:AOP 服務;

  • Spring DAO:對 JDBC 的抽象,簡化了數據訪問異常的處理;

  • Spring ORM:對現有的 ORM 框架的支持;

  • Spring Web:提供了基本的面向 Web 的綜合特性,例如多方文件上傳;

  • Spring MVC:提供面向 Web 應用的 Model-View-Controller 實現。


2、Spring 的優點?

  • spring 屬於低侵入式設計,代碼的污染極低;

  • spring 的 DI 機制將對象之間的依賴關係交由框架處理,減低組件的耦合性;

  • Spring 提供了 AOP 技術,支持將一些通用任務,如安全、事務、日誌、權限等進行集中式管理,從而提供更好的複用。

  • spring 對於主流的應用框架提供了集成支持。


3、Spring 的 AOP 理解

AOP,一般稱爲面向切面,作爲面向對象的一種補充,用於將那些與業務無關,但卻對多個對象產生影響的公共行爲和邏輯,抽取並封裝爲一個可重用的模塊,這個模塊被命名爲 “切面”(Aspect),減少系統中的重複代碼,降低了模塊間的耦合度,同時提高了系統的可維護性。可用於權限認證、日誌、事務處理。AOP 實現的關鍵在於 代理模式.

Spring AOP 中的動態代理主要有兩種方式,JDK 動態代理和 CGLIB 動態代理:

  • ①JDK 動態代理只提供接口的代理,不支持類的代理。核心 InvocationHandler 接口和 Proxy 類,InvocationHandler 通過 invoke () 方法反射來調用目標類中的代碼,動態地將橫切邏輯和業務編織在一起;接着,Proxy 利用 InvocationHandler 動態創建一個符合某一接口的的實例, 生成目標類的代理對象。

  • ②如果代理類沒有實現 InvocationHandler 接口,那麼 Spring AOP 會選擇使用 CGLIB 來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態的生成指定類的一個子類對象,並覆蓋其中特定方法並添加增強代碼,從而實現 AOP。CGLIB 是通過繼承的方式做的動態代理,因此如果某個類被標記爲 final,那麼它是無法使用 CGLIB 做動態代理的。


4、Spring 的 IoC 理解:

  • IOC 就是控制反轉,是指創建對象的控制權的轉移,以前創建對象的主動權和時機是由自己把控的,而現在這種權力轉移到 Spring 容器中,並由容器根據配置文件去創建實例和管理各個實例之間的依賴關係,對象與對象之間鬆散耦合,也利於功能的複用。DI 依賴注入,和控制反轉是同一個概念的不同角度的描述,即 應用程序在運行時依賴 IoC 容器來動態注入對象需要的外部資源。

  • 最直觀的表達就是,IOC 讓對象的創建不用去 new 了,可以由 spring 自動生產,使用 java 的反射機制,根據配置文件在運行時動態的去創建對象以及管理對象,並調用對象的方法的。

  • Spring 的 IOC 有三種注入方式 :構造器注入、setter 方法注入、根據註解注入。

  • IoC 讓相互協作的組件保持鬆散的耦合,而 AOP 編程允許你把遍佈於應用各層的功能分離出來形成可重用的功能組件。


5、BeanFactory 和 ApplicationContext 有什麼區別?

BeanFactory 和 ApplicationContext 是 Spring 的兩大核心接口,都可以當做 Spring 的容器。其中 ApplicationContext 是 BeanFactory 的子接口。

(1)功能

  • BeanFactory:是 Spring 裏面最底層的接口,包含了各種 Bean 的定義,讀取 bean 配置文檔,管理 bean 的加載、實例化,控制 bean 的生命週期,維護 bean 之間的依賴關係。

  • ApplicationContext
    接口作爲 BeanFactory 的派生,除了提供 BeanFactory 所具有的功能外,還提供了更完整的框架功能:

    • 繼承 MessageSource,因此支持國際化。

    • 統一的資源文件訪問方式。

    • 提供在監聽器中註冊 bean 的事件。

    • 同時加載多個配置文件。

    • 載入多個(有繼承關係)上下文 ,使得每一個上下文都專注於一個特定的層次,比如應用的 web 層。

(2)加載方式

  • BeanFactroy 採用的是延遲加載形式來注入 Bean 的,即只有在使用到某個 Bean 時 (調用 getBean ()),纔對該 Bean 進行加載實例化。這樣,我們就不能發現一些存在的 Spring 的配置問題。如果 Bean 的某一個屬性沒有注入,BeanFacotry 加載後,直至第一次使用調用 getBean 方法纔會拋出異常。

  • ApplicationContext,它是在容器啓動時,一次性創建了所有的 Bean。這樣,在容器啓動時,我們就可以發現 Spring 中存在的配置錯誤,這樣有利於檢查所依賴屬性是否注入。 ApplicationContext 啓動後預載入所有的單實例 Bean,通過預載入單實例 bean , 確保當你需要的時候,你就不用等待,因爲它們已經創建好了。

  • 相對於基本的 BeanFactory,ApplicationContext 唯一的不足是佔用內存空間。當應用程序配置 Bean 較多時,程序啓動較慢。

(3)BeanFactory 通常以編程的方式被創建,ApplicationContext 還能以聲明的方式創建,如使用 ContextLoader。

(4)BeanFactory 和 ApplicationContext 都支持 BeanPostProcessor、BeanFactoryPostProcessor 的使用,但兩者之間的區別是:BeanFactory 需要手動註冊,而 ApplicationContext 則是自動註冊。


6、請解釋 Spring Bean 的生命週期?

Spring 上下文中的 Bean 生命週期也類似,如下:

(1)實例化 Bean:

對於 BeanFactory 容器,當客戶向容器請求一個尚未初始化的 bean 時,或初始化 bean 的時候需要注入另一個尚未初始化的依賴時,容器就會調用 createBean 進行實例化。對於 ApplicationContext 容器,當容器啓動結束後,通過獲取 BeanDefinition 對象中的信息,實例化所有的 bean。

(2)設置對象屬性(依賴注入):

實例化後的對象被封裝在 BeanWrapper 對象中,緊接着,Spring 根據 BeanDefinition 中的信息 以及 通過 BeanWrapper 提供的設置屬性的接口完成依賴注入。

(3)處理 Aware 接口:

接着,Spring 會檢測該對象是否實現了 xxxAware 接口,並將相關的 xxxAware 實例注入給 Bean:

  • 如果這個 Bean 已經實現了 BeanNameAware 接口,會調用它實現的 setBeanName (String beanId) 方法,此處傳遞的就是 Spring 配置文件中 Bean 的 id 值;

  • 如果這個 Bean 已經實現了 BeanFactoryAware 接口,會調用它實現的 setBeanFactory () 方法,傳遞的是 Spring 工廠自身。

  • 如果這個 Bean 已經實現了 ApplicationContextAware 接口,會調用 setApplicationContext (ApplicationContext) 方法,傳入 Spring 上下文;

(4)BeanPostProcessor:

如果想對 Bean 進行一些自定義的處理,那麼可以讓 Bean 實現了 BeanPostProcessor 接口,那將會調用 postProcessBeforeInitialization (Object obj, String s) 方法。

(5)InitializingBean 與 init-method:

如果 Bean 在 Spring 配置文件中配置了 init-method 屬性,則會自動調用其配置的初始化方法。

(6)如果這個 Bean 實現了 BeanPostProcessor 接口,將會調用 postProcessAfterInitialization (Object obj, String s) 方法;由於這個方法是在 Bean 初始化結束時調用的,所以可以被應用於內存或緩存技術;

以上幾個步驟完成後,Bean 就已經被正確創建了,之後就可以使用這個 Bean 了。

(7)DisposableBean:

當 Bean 不再需要時,會經過清理階段,如果 Bean 實現了 DisposableBean 這個接口,會調用其實現的 destroy () 方法;

(8)destroy-method:

最後,如果這個 Bean 的 Spring 配置中配置了 destroy-method 屬性,會自動調用其配置的銷燬方法。


7、 解釋 Spring 支持的幾種 bean 的作用域。

Spring 容器中的 bean 可以分爲 5 個範圍:

(1)singleton:默認,每個容器中只有一個 bean 的實例,單例的模式由 BeanFactory 自身來維護。

(2)prototype:爲每一個 bean 請求提供一個實例。

(3)request:爲每一個網絡請求創建一個實例,在請求完成以後,bean 會失效並被垃圾回收器回收。

(4)session:與 request 範圍類似,確保每個 session 中有一個 bean 的實例,在 session 過期後,bean 會隨之失效。

(5)global-session:全局作用域,global-session 和 Portlet 應用相關。當你的應用部署在 Portlet 容器中工作時,它包含很多 portlet。如果你想要聲明讓所有的 portlet 共用全局的存儲變量的話,那麼這全局變量需要存儲在 global-session 中。全局作用域與 Servlet 中的 session 作用域效果相同。


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

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

9、Spring 如何處理線程併發問題?

  • 在一般情況下,只有無狀態的 Bean 纔可以在多線程環境下共享,在 Spring 中,絕大部分 Bean 都可以聲明爲 singleton 作用域,因爲 Spring 對一些 Bean 中非線程安全狀態採用 ThreadLocal 進行處理,解決線程安全問題。

  • ThreadLocal 和線程同步機制都是爲了解決多線程中相同變量的訪問衝突問題。同步機制採用了 “時間換空間” 的方式,僅提供一份變量,不同的線程在訪問前需要獲取鎖,沒獲得鎖的線程則需要排隊。而 ThreadLocal 採用了 “空間換時間” 的方式。

  • ThreadLocal 會爲每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問衝突。因爲每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal 提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進 ThreadLocal。


10、Spring 基於 xml 注入 bean 的幾種方式:

(1)Set 方法注入;

(2)構造器注入:①通過 index 設置參數的位置;②通過 type 設置參數類型;

(3)靜態工廠注入;獲取依舊是set方法,但是配置文件指向的是工廠類

(4)實例工廠;


10、Spring 的自動裝配:

在 spring 中,對象無需自己查找或創建與其關聯的其他對象,由容器負責把需要相互協作的對象引用賦予各個對象,使用 autowire 來配置自動裝載模式。

在 Spring 框架 xml 配置中共有 5 種自動裝配:

(1)no:默認的方式是不進行自動裝配的,通過手工設置 ref 屬性來進行裝配 bean。

(2)byName:通過 bean 的名稱進行自動裝配,如果一個 bean 的 property 與另一 bean 的 name 相同,就進行自動裝配。

(3)byType:通過參數的數據類型進行自動裝配。

(4)constructor:利用構造函數進行裝配,並且構造函數的參數通過 byType 進行裝配。

(5)autodetect:自動探測,如果有構造方法,通過 construct 的方式自動裝配,否則使用 byType 的方式自動裝配。

基於註解的方式:

使用 @Autowired 註解來自動裝配指定的 bean。在使用 @Autowired 註解之前需要在 Spring 配置文件進行配置,<context:annotation-config />。在啓動 spring IoC 時,容器自動裝載了一個 AutowiredAnnotationBeanPostProcessor 後置處理器,當容器掃描到 @Autowied、@Resource 或 @Inject 時,就會在 IoC 容器自動查找需要的 bean,並裝配給該對象的屬性。在使用 @Autowired 時,首先在容器中查詢對應類型的 bean:

如果查詢結果剛好爲一個,就將該 bean 裝配給 @Autowired 指定的數據;

如果查詢的結果不止一個,那麼 @Autowired 會根據名稱來查找;

如果上述查找的結果爲空,那麼會拋出異常。解決方法時,使用 required=false。

@Autowired 可用於:構造函數、成員變量、Setter 方法

注:@Autowired 和 @Resource 之間的區別

(1) @Autowired 默認是按照類型裝配注入的,默認情況下它要求依賴對象必須存在(可以設置它 required 屬性爲 false)。

(2) @Resource 默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的 bean 纔會按照類型來裝配注入。


11、Spring 框架中都用到了哪些設計模式?

(1)工廠模式:BeanFactory 就是簡單工廠模式的體現,用來創建對象的實例;

(2)單例模式:Bean 默認爲單例模式。

(3)代理模式:Spring 的 AOP 功能用到了 JDK 的動態代理和 CGLIB 字節碼生成技術;

(4)模板方法:用來解決代碼重複的問題。比如. RestTemplate, JmsTemplate, JpaTemplate。

(5)觀察者模式:定義對象鍵一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都會得到通知被制動更新,如 Spring 中 listener 的實現 --ApplicationListener。


12、Spring 事務的實現方式和實現原理:

Spring 事務的本質其實就是數據庫對事務的支持,沒有數據庫的事務支持,spring 是無法提供事務功能的。真正的數據庫層的事務提交和回滾是通過 binlog 或者 redo log 實現的。

(1)Spring 事務的種類:

spring 支持編程式事務管理和聲明式事務管理兩種方式:

①編程式事務管理使用 TransactionTemplate。

②聲明式事務管理建立在 AOP 之上的。其本質是通過 AOP 功能,對方法前後進行攔截,將事務處理的功能編織到攔截的方法中,也就是在目標方法開始之前加入一個事務,在執行完目標方法之後根據執行情況提交或者回滾事務。

  • 聲明式事務最大的優點就是不需要在業務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關的事務規則聲明或通過 @Transactional 註解的方式,便可以將事務規則應用到業務邏輯中。

  • 聲明式事務管理要優於編程式事務管理,這正是 spring 倡導的非侵入式的開發方式,使業務代碼不受污染,只要加上註解就可以獲得完全的事務支持。唯一不足地方是,最細粒度只能作用到方法級別,無法做到像編程式事務那樣可以作用到代碼塊級別。

(2)spring 的事務傳播行爲:

spring 事務的傳播行爲說的是,當多個事務同時存在的時候,spring 如何處理這些事務的行爲。

  • PROPAGATION_REQUIRED:如果當前沒有事務,就創建一個新事務,如果當前存在事務,就加入該事務,該設置是最常用的設置。

  • PROPAGATION_SUPPORTS:支持當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就以非事務執行。‘

  • PROPAGATION_MANDATORY:支持當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就拋出異常。

  • PROPAGATION_REQUIRES_NEW:創建新事務,無論當前存不存在事務,都創建新事務。

  • PROPAGATION_NOT_SUPPORTED:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

  • PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則拋出異常。

(3)Spring 中的隔離級別:

  • ISOLATION_DEFAULT:這是個 PlatfromTransactionManager 默認的隔離級別,使用數據庫默認的事務隔離級別。

  • ISOLATION_READ_UNCOMMITTED:讀未提交,允許另外一個事務可以看到這個事務未提交的數據。

  • ISOLATION_READ_COMMITTED:讀已提交,保證一個事務修改的數據提交後才能被另一事務讀取,而且能看到該事務對已有記錄的更新。

  • ISOLATION_REPEATABLE_READ:可重複讀,保證一個事務修改的數據提交後才能被另一事務讀取,但是不能看到該事務對已有記錄的更新。

  • ISOLATION_SERIALIZABLE:一個事務在執行的過程中完全看不到其他事務對數據庫所做的更新。


13、Spring 框架中有哪些不同類型的事件?

Spring 提供了以下 5 種標準的事件:

(1)上下文更新事件(ContextRefreshedEvent):在調用 ConfigurableApplicationContext 接口中的 refresh () 方法時被觸發。

(2)上下文開始事件(ContextStartedEvent):當容器調用 ConfigurableApplicationContext 的 Start () 方法開始 / 重新開始容器時觸發該事件。

(3)上下文停止事件(ContextStoppedEvent):當容器調用 ConfigurableApplicationContext 的 Stop () 方法停止容器時觸發該事件。

(4)上下文關閉事件(ContextClosedEvent):當 ApplicationContext 被關閉時觸發該事件。容器被關閉時,其管理的所有單例 Bean 都被銷燬。

(5)請求處理事件(RequestHandledEvent):在 Web 應用中,當一個 http 請求(request)結束觸發該事件。

如果一個 bean 實現了 ApplicationListener 接口,當一個 ApplicationEvent 被髮布以後,bean 會自動被通知。


14、解釋一下 Spring AOP 裏面的幾個名詞:

(1)切面(Aspect):被抽取的公共模塊,可能會橫切多個對象。 在 Spring AOP 中,切面可以使用通用類(基於模式的風格) 或者在普通類中以 @AspectJ 註解來實現。

(2)連接點(Join point):指方法,在 Spring AOP 中,一個連接點 總是 代表一個方法的執行。

(3)通知(Advice):在切面的某個特定的連接點(Join point)上執行的動作。通知有各種類型,其中包括 “around”、“before” 和 “after” 等通知。許多 AOP 框架,包括 Spring,都是以攔截器做通知模型, 並維護一個以連接點爲中心的攔截器鏈。

(4)切入點(Pointcut):切入點是指 我們要對哪些 Join point 進行攔截的定義。通過切入點表達式,指定攔截的方法,比如指定攔截 add*、search*。

(5)引入(Introduction):(也被稱爲內部類型聲明(inter-type declaration))。聲明額外的方法或者某個類型的字段。Spring 允許引入新的接口(以及一個對應的實現)到任何被代理的對象。例如,你可以使用一個引入來使 bean 實現 IsModified 接口,以便簡化緩存機制。

(6)目標對象(Target Object): 被一個或者多個切面(aspect)所通知(advise)的對象。也有人把它叫做 被通知(adviced) 對象。 既然 Spring AOP 是通過運行時代理實現的,這個對象永遠是一個 被代理(proxied) 對象。

(7)織入(Weaving):指把增強應用到目標對象來創建新的代理對象的過程。Spring 是在運行時完成織入。


15、Spring 通知有哪些類型?

(1)前置通知(Before advice):在某連接點(join point)之前執行的通知,但這個通知不能阻止連接點前的執行(除非它拋出一個異常)。

(2)返回後通知(After returning advice):在某連接點(join point)正常完成後執行的通知:例如,一個方法沒有拋出任何異常,正常返回。

(3)拋出異常後通知(After throwing advice):在方法拋出異常退出時執行的通知。

(4)後通知(After (finally) advice):當某連接點退出的時候執行的通知(不論是正常返回還是異常退出)。

(5)環繞通知(Around Advice):包圍一個連接點(join point)的通知,如方法調用。這是最強大的一種通知類型。 環繞通知可以在方法調用前後完成自定義的行爲。它也會選擇是否繼續執行連接點或直接返回它們自己的返回值或拋出異常來結束執行。 環繞通知是最常用的一種通知類型。大部分基於攔截的 AOP 框架,例如 Nanning 和 JBoss4,都只提供環繞通知。

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