1. 程式人生 > >Spring 框架面試題總結

Spring 框架面試題總結

一. 什麼是Spring?

答:spring的核心是一個輕量級的容器(Container),它是實現IoC(Inversion of Control)容器和非侵入性(No intrusive)的框架,並提供AOP(Aspect-oriented Programming)的實現方式,提供對持久層(Persistence)、事務(Transcation)的支援;提供MVC Web框架的實現,並對一些常用的企業服務API提供了一致的模型封裝,是一個全方位的應用程式框架,除此之外,對現存的各種框架(Structs、JSF、hibernate、Ibatis、Webwork等),Spring也提供了與他們相整合的方案。 
細化: 
1、Spring的核心是一個輕量級(Lightweight)的容器(Container)。 
2、Spring是實現IoC(Inversion of Control)容器和非入侵性(No intrusive)的框架。 
3、Spring提供AOP(Aspect-oriented programming)的實現方式,把應用業務邏輯和系統服務分開。 
4、Spring提供對持久層(Persistence)、事物(Transcation)的支援。 
5、Spring供MVC Web框架的實現,並對一些常用的企業服務API(Application Interface)提供一致的模型封裝。 
6、Spring提供了對現存的各種框架(Structs、JSF、Hibernate、Ibatis、Webwork等)相整合的方案。 
總之,Spring是一個全方位的應用程式框架。

二、Spring的核心

1、IoC/DI(控制反轉/依賴注入):
1)控制反轉可以分開來解讀,控制和反轉-> 首先控制什麼?對什麼進行控制? 其實此處的控制指的是程式中的一些物件或者變數的控制權,在傳統的程式中都是由應用程式自己控制物件建立或者變數賦值,這是一種主動式的控制,導致元件之間的完全耦合;現在將一些物件或者變數的建立控制權交給一個叫做Ioc容器的東西,由這個容器來控制應用程式中所需要的資源,這樣就變成了被動的控制,對元件之間的關係進行解耦,所以所謂的反轉就是將控制權由應用程式轉交到Ioc容器。 
2)依賴注入:同樣將DI分開來解讀,依賴和注入-> 首先依賴什麼?誰依賴誰? 其實應用程式中所需要的資源建立和獲取都是要依賴於Ioc容器,需要IoC容器裝配類之間的關係,即應用程式依賴於IoC容器的裝配功能;相反,注入就是IoC容器嚮應用程式中進行注入應用程式所需要的資源,由應用程式主動裝配物件的依賴變應用程式被動接受依賴,所以IoC容器也叫DI容器。

綜上所述,控制權的主動與被動式其實都是相對於(參考物)IoC容器來說的,也可以將IoC模式看做是工廠模式的昇華,不同的是Spring中的控制反轉所用到的是Java的“反射”技術,通過在XML檔案中定義應用程式所需要的類,再由IoC容器根據xml檔案建立這些物件。所以這也形成了工廠與物件生成這兩者獨立分隔開,目的就是提高靈活性和可維護性。之所以將物件生成放到xml檔案中,如果我們想要換一個實現的類將變得很簡單,只需要修改xml檔案即可。 
2、AOP(面向切面程式設計):將具體的通用的應用從業務邏輯中分離出來,各自做各自專業的事情。 
1)切面:簡單的理解就是一個類,每個或者物件 
2)連線點:類中的方法(可以切入的地方) 
3)通知:切面在某個連線點執行的操作(分為: Before advice , After returning advice , After throwing advice , After (finally) advice , Around advice ); 
4)切入點:符合切點表示式的連線點,也就是真正被切入的地方 
5)引入: 
6)目標物件:

三、Spring能做什麼?

四、Spring注入Bean的方式

(1)設值注入(set方法) 
(2)構造器注入 
(3)工廠方法 
Spring載入Bean的流程: 
(1)建立一個上下文context = createApplicationContext; 
(2)context中都會有一個BeanFactory(預設是DefaultListableBeanFactory),在該類的子類類xmlBeanFactory中進行xml檔案的解析; 
(3)在類XmlBeanDefinitionParser 中用Dom解析xml檔案(DefaultXmlBeanDefinitionParser),解析xml檔案中所有bean,並將bean放到BeanDefinitionHolder中,封裝成BeanDefinition; 
(4)再進行bean的註冊,具體在BeanDefinitionReaderUtils類呼叫DefaultListableBeanFactory類的registerBeanDefinition進行bean的註冊,在這裡用了一HashMap存放bean,其中用Beanname作為鍵值,其封裝好的beanDefinition作為值。還有用一個List存放所有的bean的名字。

設值注入和構造器注入的區別

1) 在設定注入需要該Bean包含這些屬性的setter方法; 
2) 與傳統的JavaBean的寫法更相似,程式開發人員更容易理解、接收。通過setter方法設定依賴關係顯得更加只管; 
3) 對於複雜的依賴關係,如果採用構造注入,會導致構造器引數列表複雜,難以閱讀。Spring在建立Bean例項時,需要同時例項化其它依賴的全部例項,因而導致效能下降。而使用設值注入,則能避免這些問題; 
4) 尤其是在某些屬性可選的情況況下,多引數的構造器顯得更加複雜; 
但是在其他的場景,構造器注入顯得更好的效能: 
1) 構造注入需要該Bean包含帶有這些屬性的構造器; 
2) 構造注入可以在構造器中決定依賴關係的注入順序,優先依賴的優先注入; 
3) 對於依賴關係無需變化的Bean,構造注入更有用處。因為沒有Setter方法,所有的依賴關係全部在構造器內設定。因此,無需擔心後續的程式碼對依賴關係產生破壞 
4) 依賴關係只能在構造器中設定,則只有元件的建立者才能改變元件的依賴關係。對元件的呼叫者而言,元件內部的依賴關係完全透明,更符合高內聚的原則.

(1)在使用設值注入時有可能還不能保證某種依賴是否已經被注入,也就是說這時物件的依賴關係有可能是不完整的。而在另一種情況下,構造器注入則不允許生成依賴關係不完整的物件。 
(2)在設值注入時如果物件A和物件B互相依賴,在建立物件A時Spring會丟擲sObjectCurrentlyInCreationException異常,因為在B物件被建立之前A物件是不能被建立的,反之亦然。所以Spring用設值注入的方法解決了迴圈依賴的問題,因物件的設值方法是在物件被建立之前被呼叫的。

注:採用以設值注入為主,構造注入為輔的注入策略。對於依賴關係無需變化的注入,儘量採用構造注入;而其他的依賴關係的注入,則考慮採用設值注入。

五、Bean的生命週期(以BeanFactory)

1) Bean的建立,由BeanFactory讀取Bean定義檔案,並建立Bean例項; 
2) 執行Bean的屬性注入,Setter注入; 
3) 如果Bean類實現了org.springframework.beans.factory.BeanNameAware介面,則執行其setBeanName方法; 
4) 如果Bean類實現了org.springframework.beans.factory.BeanFactoryAware介面,則執行其setBeanFactory方法; 
5) 如果容器中有實現org.springframework.beans.factory.BeanPostProcessors介面的例項,則任何Bean在初始化之前都會執行這個例項的processBeforeInitialization()方法; 
6) 如果Bean類實現了org.springframework.beans.factory.InitializingBean介面,則執行其afterPropertiesSet()方法; 
7) 呼叫Bean的初始化方法”init-method” (!!注意,init-method方法沒有引數); 
8) 如果容器中有實現org.springframework.beans.factory.BeanPostProcessors介面的例項,則任何Bean在初始化之後都會執行這個例項的processAfterInitialization()方法; 
9) 使用Bean做一些業務邏輯…. 
10) 使用完,容器關閉,如果Bean類實現了org.springframework.beans.factory.DisposableBean介面,則執行它的destroy()方法; 
11) 在容器關閉時,可以在Bean定義檔案中使用“destory-method”定義的方法,銷燬Bean (!!注意,destory-method方法沒有引數);

ApplicationContext中bean的生命週期也是類似的。

六、BeanFactory 和ApplicationContext的區別

  1. 首先BeanFactory和ApplicationContext都是介面,並且ApplicationContext是BeanFactory的子介面。
  2. 其次BeanFactory是Spring中最底層的介面,提供了最簡單的容器的功能,只提供了例項化物件和拿物件的功能, 
    ApplicationContext(應用上下文)它是Spring的一個更高階的容器,提供了更多的有用的功能; 
    1)ApplicationContext繼承了BeanFactory介面,所以,ApplicationContext也能像BeanFactory從容器中得到Bean(繼承至 ListableBeanFactory); 
    2)ApplicationContext提供的額外的功能: 
    國際化的功能,訊息傳送、響應機制(繼承至MessageSource );統一載入資源的功能(繼承至ResourceLoader);強大的事件機制( 繼承至ApplicationEventPublisher);對Web應用的支援()
  3. 它們的載入方式不同: 
    1) BeanFactory採用的是延遲載入的形式來注入Bean,即只有在使用某個bean的時候,才對該Bean進行載入例項化.好處是節約記憶體,缺點是速度比較慢. 
    2) ApplicationContext則相反的,它是在Ioc容易啟動時就一次性建立所有的Bean,這樣的好處是可以馬上發現Spring配置檔案中的錯誤。壞處就是浪費記憶體。

ApplicationContext的三種較常見的實現方式: 
1) ClassPathXmlApplicationContext:從classpath的xml配置檔案中讀取上下文,並生成上下文定義,應用程式上下文從程式環境中取得。

ApplicationContext context = new ClassPathXmlApplicationContext("****.xml");
  • 1
  • 1

2) FileSystemXmlApplicationContext:由檔案系統中的xml配置檔案讀取上下文。

ApplicationContext context = new FileSystemXmlApplicationContext("****.xml");
  • 1
  • 1

3) XmlWebApplicationContext:由Web應用的Xml檔案讀取上下文。

七、Spring Bean的作用域

1) Singleton: 這是預設的作用域,這種範圍確保不管接受多少個請求,每個容器中只有一個bean的例項,單例模式有BeanFactory自身維護; 
2) Prototype: 原形範圍與單例範圍相反,為每一個bean請求提供一個例項; 
3) Request: 在請求bean範圍內會為每一個來自客戶端的網路請求建立一個例項,在請求完成以後,bean會失效並被垃圾回收器回收; 
4) Session: 與請求範圍類似,確保每個session中有一個bean的例項,在session過期後,bean會隨之失效; 
5) global-session: global-session和Portlet應用相關。當你的應用部署在Portlet容器中工作時,它包含很多portlet。如果你想要宣告讓所有的portlet共用全域性的儲存變數的話,那麼這全域性變數需要儲存在global-session中。

八、Bean的自動裝配模式

  1. no: spring預設的設定,在該設定下自動裝配是關閉的,開發者需要在配置檔案中用標籤明確依賴關係;
  2. byName: 該選項可以根據bean名稱設定依賴關係。當向一個bean中自動裝配一個屬性時,容器將根據bean的名稱自動在在配置檔案中查詢一個匹配的bean。如果找到的話,就裝配這個屬性,如果沒找到的話就報錯。
  3. byType: 該選項可以根據bean型別設定依賴關係。當向一個bean中自動裝配一個屬性時,容器將根據bean的型別自動在在配置檔案中查詢一個匹配的bean。如果找到的話,就裝配這個屬性,如果沒找到的話就報錯。
  4. constructor: 構造器自動裝載,僅僅適用於與有構造器相同引數的bean,如果在容器中沒有找到與構造器引數型別一致的bean,那麼將會丟擲異常。
  5. autodetect: 該模式自動探測使用構造器自動裝配或者byType自動裝配。先嚐試找合適的帶引數的建構函式,若沒有則自動選擇byType的自動裝配模式。

基於註解的自動裝配,spring預設是關閉註解模式的,所以需要在配置檔案中設定

九、各種註解的解釋

  1. @Required: 驗證bean是否被正確的設定了,需要在Ioc容器中註冊RequiredAnnotationBeanPostProcessor,它是Spring中的後置處理用來驗證被@Required 註解的bean屬性是否被正確的設定了,若沒有屬性被@Required註解過的話,後置處理器會丟擲一個BeanInitializationException異常。 

  2. @AutoWired: 該註解用於在bean的設值方法上自動裝配bean的屬性,一個引數或者帶有任意名稱或帶有多個引數的方法。(嘗試用byType 自動裝配)

  3. @Qualifer: 該註解一般和@AutoWired一起使用,用於幫助Ioc容器能知道當前註解的屬性應該自動裝配哪一個。(對於在xml檔案中定義了多個同類的bean,但是id不同,若單單用@AutoWired進行註解,Ioc容器無法分辨出應該自動裝配哪一個bean)

十、Spring 中的所有哪些不同型別的事件?

Spring的ApplicationContext提供了支援事務和程式碼中新增監聽器的功能。 
可以建立一個bean其實現ApplicationListener介面(型別是ApplicationEvent),當一個ApplicationEvent 被髮布後,bean就自動被通知,並且在方法onApplicationEvent(…)方法中處理該事件。

public class AllApplicationEventListener implements ApplicationListener < ApplicationEvent >
{
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent)
    {
        //process event
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在Spring中有5中標準的事件: 
1. 上下文更新事件(ContextRefreshedEvent):該事件會在ApplicationContext被初始化或者更新時釋出,也可以在呼叫ConfigurableApplicationContext介面中的refresh()方法時被觸發。 
2. 上下文開始事件(ContextStartedEvent): 當容器呼叫ConfigurableApplicationContext的Start()方法開始/重新開始容器時被觸發。 
3. 上下文停止事件(ContextStoppedEvent): 當容器呼叫ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。 
4. 上下文關閉事件(ContextClosedEvent): 當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷燬。 
5. 請求處理事件(RequestHandledEvent): 在Web應用中,當一個http請求(request)結束觸發該事件。

spring也讓使用者可以自定義事件型別,繼承ApplicationEvent。

public class CustomApplicationEvent extends ApplicationEvent
{
    public CustomApplicationEvent ( Object source, final String msg )
    {
        super(source);
        System.out.println("Created a Custom event");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

為了監聽這個事件,還需要建立一個監聽器:

public class CustomEventListener implements ApplicationListener < CustomApplicationEvent >
{
    @Override
    public void onApplicationEvent(CustomApplicationEvent applicationEvent) {
        //handle event
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

之後通過applicationContext介面的publishEvent()方法來發布自定義事件。

CustomApplicationEvent customEvent = new CustomApplicationEvent(applicationContext, "Test message");
applicationContext.publishEvent(customEvent);
  • 1
  • 2
  • 1
  • 2

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

  1. 代理模式—在AOP和remoting中被用的比較多。
  2. 單例模式—在spring配置檔案中定義的bean預設為單例模式。
  3. 模板方法—用來解決程式碼重複的問題。比如. RestTemplate, JmsTemplate, JpaTemplate。
  4. 前端控制器—Spring提供了DispatcherServlet來對請求進行分發。
  5. 檢視幫助(View Helper )—Spring提供了一系列的JSP標籤,高效巨集來輔助將分散的程式碼整合在視圖裡。
  6. 依賴注入—貫穿於BeanFactory / ApplicationContext介面的核心理念。
  7. 工廠模式—BeanFactory用來建立物件的例項。