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種標準的事件:
- 上下文更新事件(ContextRefreshedEvent):在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發。
- 上下文開始事件(ContextStartedEvent):當容器調用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。
- 上下文停止事件(ContextStoppedEvent):當容器調用ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。
- 上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷燬。
- 請求處理事件(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 事務爲何失效可能原因:
- MySQL 使用的是 MyISAM 引擎,而 MyISAM 是不支持事務的。需要支持使用可以使用 InnoDB 引擎
- 如果使用了 Spring MVC ,context:component-scan 重複掃描問題可能會引起事務失敗
- @Transactional 註解開啓配置放到 DispatcherServlet 的配置裏了。
- @Transactional 註解只能放在public修飾的方法上才起作用,如果放在其他非public(private,protected)方法上,雖然不報錯,但是事務不起作用
- @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方式:
- byName:根據bean的名稱進行注入
- byType:根據類型進行注入
- 構造函數:通過構造函數來注入依賴項 需要設置大量參數
<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。
文章參考: