Spring基礎框架四:常見高頻Spring面試題

10道Spring核心面試題

  • Spring IoC、AOP 原理
  • Spring Bean 生命週期
  • Spring Bean 注入是如何解決循環依賴問題的
  • 怎樣用註解的方式配置 Spring?
  • Spring 事務爲何失效了
  • SpringMVC 的流程?
  • Springmvc 的優點:
  • Spring 通知類型使用場景分別有哪些?
  • IoC 控制反轉設計原理?
  • Spring 如何處理線程併發問題?

常見Spring核心面試題

1 什麼是Spring框架?Spring框架有哪些主要模塊?

2 使用Spring框架能帶來哪些好處?

3 什麼是控制反轉(IOC)?什麼是依賴注入?

4 在Java中依賴注入有哪些方式?

5 BeanFactory和ApplicationContext有什麼區別?

6 Spring提供幾種配置方式來設置元數據?

7 如何使用XML配置的方式配置Spring?

8 Spring提供哪些配置形式?

9 怎樣用註解的方式配置Spring?

10 請解釋Spring Bean的生命週期?

11 Spring Bean作用域的區別是什麼?

12 什麼是Spring Inner Bean?

13 Spring框架中的單例Bean是線程安全的嗎?

14 請舉例說明如何在Spring中注入一個Java 集合?

15 如何向Spring Bean中注入java.util.Properties?

16 請解釋Spring Bean的自動裝配?

17 自動裝配有哪些侷限性?

18 請解釋各種自動裝配模式的區別?

19 請舉例解釋@Required Annotation?

20 請舉例說明@Qualifier註解?

21 構造方法注入和設值注入有什麼區別?

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

23 FileSystemResource和ClassPathResource有何區別?

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

25 在Spring框架中如何更有效地使用JDBC?使用模板類JdbcTemplete

26 請解釋下Spring框架中的IOC容器?

27 在Spring中可以注入或空字符串嗎?

針對其中個別問題進行解答

FileSystemResource和ClassPathResource有何區別

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

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

Spring的ApplicationContext 提供了支持事件和代碼中監聽器的功能。即事件監聽和事件派發。我們可以創建bean用來監聽在ApplicationContext 中發佈的事件。ApplicationEvent類和在ApplicationContext接口中處理的事件,如果一個bean實現了ApplicationListener接口,當一個ApplicationEvent 被髮布以後,bean會自動被通知。

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

  1. 上下文更新事件(ContextRefreshedEvent):在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發。
  2. 上下文開始事件(ContextStartedEvent):當容器調用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。
  3. 上下文停止事件(ContextStoppedEvent):當容器調用ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。
  4. 上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷燬。
  5. 請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。

在Spring中可以注入或空字符串嗎?

<bean id="map" class="xxx">

<!-- 注入空字符串值 -->
<property name="emptyValue">
   <value></value>
</property>

<!-- 注入null值 -->
<property name="nullValue"><null/></property>
</bean>

Spring @Required 註釋

@Required 註釋應用於 bean 屬性的 setter 方法,它表明受影響的 bean 屬性在配置時必須放在 XML 配置文件中,否則容器就會拋出一個 BeanInitializationException 異常。

Spring 事務爲何失效可能原因:

  1. MySQL 使用的是 MyISAM 引擎,而 MyISAM 是不支持事務的。需要支持使用可以使用 InnoDB 引擎
  2. 如果使用了 Spring MVC ,context:component-scan 重複掃描問題可能會引起事務失敗
  3. @Transactional 註解開啓配置放到 DispatcherServlet 的配置裏了。
  4. @Transactional 註解只能放在public修飾的方法上才起作用,如果放在其他非public(private,protected)方法上,雖然不報錯,但是事務不起作用
  5. @Transactional 同一個類中無事務方法 a() 內部調用有事務方法 b(),那麼此時事物不生效。

Spring 如何處理線程併發問題

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

BeanFactory和ApplicationContext有什麼區別?

1. BeanFactory負責讀取bean配置文檔,管理bean的加載,實例化,維護bean之間的依賴關係,負責bean的生命週期。

2. ApplicationContext是BeanFactory的子類,除了提供上述BeanFactory所能提供的功能之外,還提供了其他的功能:

  • 提供了支持國際化的文本消息
  • 統一的資源文件讀取方式
  • 已在監聽器中註冊的 bean 的事件

3. BeanFactory提供懶加載方式,ApplicationContext採用的是預加載,每個Bean都在ApplicationContext啓動後實例化。

 請解釋Spring Bean的自動裝配?自動裝配有哪些侷限性?請解釋各種自動裝配模式的區別?

通常Bean的屬性配置通過Setter和構造器,Spring爲我們提供了自動裝配的機制,autowire的模式。

侷限性:基本數據類型的值、字符串字面量、類字面量無法使用自動裝配來注入。模糊特性:自動裝配不如顯式裝配精確,如果有可能,建議使用顯式裝配。

spring 自動裝配 bean方式:

  1. byName:根據bean的名稱進行注入
  2. byType:根據類型進行注入
  3. 構造函數:通過構造函數來注入依賴項 需要設置大量參數
<bean id="person" class="constxiong.Person" autowire="byName"></bean>
<bean id="person" class="constxiong.Person" autowire="byType"></bean>
<bean id="person" class="constxiong.Person" autowire="constructor"></bean>

Spring中單例Bean是線程安全的嗎?

Spring容器中的Bean是否線程安全,容器本身並沒有提供Bean的線程安全策略,因此可以說Spring容器中的Bean本身不具備線程安全的特性,但是具體還是要結合具體scope的Bean去研究。

prototype:原型Bean
對於原型Bean,每次創建一個新對象,也就是線程之間並不存在Bean共享,自然是不會有線程安全的問題。

單例Bean
對於單例Bean,所有線程都共享一個單例實例Bean,因此是存在資源的競爭。如果單例Bean,是一個無狀態Bean,也就是線程中的操作不會對Bean的成員執行查詢以外的操作,那麼這個單例Bean是線程安全的對於有狀態的bean,Spring官方提供的bean,一般提供了通過ThreadLocal去解決線程安全的方法,比如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等。

使用ThreadLocal的好處
使得多線程場景下,多個線程對這個單例Bean的成員變量並不存在資源的競爭,因爲ThreadLocal爲每個線程保存線程私有的數據。這是一種以空間換時間的方式。

什麼是 spring 的內部 bean?

假設我們有一個 Student 類,其中引用了 Person 類屬性,這個Person 類屬性就是內部Bean。

public class Student {
 private Person person;
}
public class Person {
 private String name;
 private String address;
}

Spring Bean 注入是如何解決循環依賴問題的

Spring對於循環依賴的解決不是無條件的Spring解決循環依賴的前提是:是針對scope單例並且顯式指明需要解決循環依賴的對象而且要求該對象沒有被代理過。同時Spring解決循環依賴也不是萬能以上三種情況只能解決兩種第一種在構造方法中相互依賴的情況Spring也無力迴天。對於多例“prototype”作用域Bean,Spring容器無法完成依賴注入因爲“prototype”作用域的Bean,Spring容器不進行緩存因此無法提前暴露一個創建中的Bean

Spring框架內定義的三級緩存解決了Bean之間的循環依賴。對於單例對象來說,在Spring的整個容器的生命週期內有且只存在一個對象,這個對象存在Cache中,Spring大量運用了Cache的手段,在循環依賴問題的解決過程中甚至使用了“三級緩存”

Spring循環依賴的理論依據

Spring循環依賴的理論依據其實是Java基於引用傳遞當我們獲取到對象的引用時,對象的field或者或屬性是可以延後設置

三級緩存:Spring就用這三級緩存巧妙的解決了循環依賴問題

  • singletonObjects:Cache of singleton objects: bean name --> bean instance,完成初始化的單例對象的 cache(一級緩存)
  • earlySingletonObjects:Cache of early singleton objects: bean name--> bean instance ,完成實例化但是尚未初始化的,提前暴光的單例對象的 cache (二級緩存)
  • singletonFactories : Cache of singleton factories: bean name -->ObjectFactory,進入實例化階段的單例對象工廠的 cache (三級緩存)

Bean的創建最爲核心三個方法解釋如下:

  • createBeanInstance:bean實例化,其實也就是調用對象的構造方法實例化對象
  • populateBean:屬性賦值,這一步主要是對bean的依賴屬性進行注入(@Autowired)
  • initializeBean:初始化,回到一些形如initMethod、InitializingBean等方法

獲取單例Bean過程

Spring首先從singletonObjects(一級緩存)中嘗試獲取如果獲取不到並且對象在創建中則嘗試從earlySingletonObjects(二級緩存)中獲取,如果還是獲取不到並且允許從singletonFactories通過getObject獲取,則通過singletonFactory.getObject()(三級緩存)獲取。如果獲取到了,則從singletonFactories中移除,並放入earlySingletonObjects中。其實也就是從三級緩存移動到了二級緩存

Spring循環依賴三級緩存原理分析

分析“A的某個field或者setter依賴了B的實例對象,同時B的某個field或者setter依賴了A的實例對象”這種循環依賴的情況。

A首先完成了生命週期的第一步實例化並且進入實例化階段的單例對象工廠的singletonFactories cache此時A已經實例化完成,已經可以被引用了此時進行生命週期的第二步屬性賦值,發現自己依賴對象B,此時就嘗試去get(B),發現B還沒有被create,所以走create流程,B在初始化第一步的時候發現自己依賴了對象A,於是嘗試get(A),嘗試一級緩存singletonObjects(肯定沒有,因爲A還沒初始化完全),嘗試二級緩存earlySingletonObjects(也沒有),嘗試三級緩存singletonFactories,由於A實例化時已經存入三級緩存中,所以B能夠通過ObjectFactory.getObject拿到A對象(雖然A還沒有初始化完全,但是總比沒有好呀),B拿到A對象後順利完成了初始化階段1、2、3,完全初始化之後將自己放入到一級緩存singletonObjects中。此時返回A中,A此時能拿到B的對象順利完成自己的初始化階段2、3,最終A也完成了初始化,進去了一級緩存 到此,B持有的已經是初始化完成的A,A持有的也是初始化完成的B。

文章參考:

https://blog.csdn.net/fedorafrog/article/details/104550165/

https://www.toutiao.com/a6775869522067849732/?timestamp=1586051079&app=news_article&group_id=6775869522067849732&req_id=202004050944380101290421342E7E5266

https://www.toutiao.com/a6727050408939749901/?timestamp=1586050937&app=news_article&group_id=6727050408939749901&req_id=20200405094216010129049101007E40EA

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