02.26 Java 最常見的 208 道面試題:第九模塊和第十模塊答案

九、設計模式

88. 說一下你熟悉的設計模式?

參考:常用的設計模式彙總,超詳細!

89. 簡單工廠和抽象工廠有什麼區別?

簡單工廠模式

這個模式本身很簡單而且使用在業務較簡單的情況下。一般用於小項目或者具體產品很少擴展的情況(這樣工廠類才不用經常更改)。

它由三種角色組成:

  • 工廠類角色:這是本模式的核心,含有一定的商業邏輯和判斷邏輯,根據邏輯不同,產生具體的工廠產品。如例子中的Driver類。
  • 抽象產品角色:它一般是具體產品繼承的父類或者實現的接口。由接口或者抽象類來實現。如例中的Car接口。
  • 具體產品角色:工廠類所創建的對象就是此角色的實例。在java中由一個具體類實現,如例子中的Benz、Bmw類。

來用類圖來清晰的表示下的它們之間的關係:

Java 最常見的 208 道面試題:第九模塊和第十模塊答案


抽象工廠模式:

先來認識下什麼是產品族: 位於不同產品等級結構中,功能相關聯的產品組成的家族。

Java 最常見的 208 道面試題:第九模塊和第十模塊答案


圖中的BmwCar和BenzCar就是兩個產品樹(產品層次結構);而如圖所示的BenzSportsCar和BmwSportsCar就是一個產品族。他們都可以放到跑車家族中,因此功能有所關聯。同理BmwBussinessCar和BenzBusinessCar也是一個產品族。

可以這麼說,它和工廠方法模式的區別就在於需要創建對象的複雜程度上。而且抽象工廠模式是三個裡面最為抽象、最具一般性的。抽象工廠模式的用意為:給客戶端提供一個接口,可以創建多個產品族中的產品對象。

而且使用抽象工廠模式還要滿足一下條件:

  1. 系統中有多個產品族,而系統一次只可能消費其中一族產品
  2. 同屬於同一個產品族的產品以其使用。

來看看抽象工廠模式的各個角色(和工廠方法的如出一轍):

  • 抽象工廠角色: 這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。在java中它由抽象類或者接口來實現。
  • 具體工廠角色:它含有和具體業務邏輯有關的代碼。由應用程序調用以創建對應的具體產品的對象。在java中它由具體的類來實現。
  • 抽象產品角色:它是具體產品繼承的父類或者是實現的接口。在java中一般有抽象類或者接口來實現。
  • 具體產品角色:具體工廠角色所創建的對象就是此角色的實例。在java中由具體的類來實現。




十、Spring / Spring MVC

90. 為什麼要使用 spring?

1.簡介

  • 目的:解決企業應用開發的複雜性
  • 功能:使用基本的JavaBean代替EJB,並提供了更多的企業應用功能
  • 範圍:任何Java應用


簡單來說,Spring是一個輕量級的控制反轉(IoC)和麵向切面(AOP)的容器框架。

2.輕量

從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個大小隻有1MB多的JAR文件裡發佈。並且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應用中的對象不依賴於Spring的特定類。

3.控制反轉

Spring通過一種稱作控制反轉(IoC)的技術促進了松耦合。當應用了IoC,一個對象依賴的其它對象會通過被動的方式傳遞進來,而不是這個對象自己創建或者查找依賴對象。你可以認為IoC與JNDI相反——不是對象從容器中查找依賴,而是容器在對象初始化時不等對象請求就主動將依賴傳遞給它。

4.面向切面

Spring提供了面向切面編程的豐富支持,允許通過分離應用的業務邏輯與系統級服務(例如審計(auditing)和事務(transaction)管理)進行內聚性的開發。應用對象只實現它們應該做的——完成業務邏輯——僅此而已。它們並不負責(甚至是意識)其它的系統級關注點,例如日誌或事務支持。

5.容器

Spring包含並管理應用對象的配置和生命週期,在這個意義上它是一種容器,你可以配置你的每個bean如何被創建——基於一個可配置原型(prototype),你的bean可以創建一個單獨的實例或者每次需要時都生成一個新的實例——以及它們是如何相互關聯的。然而,Spring不應該被混同於傳統的重量級的EJB容器,它們經常是龐大與笨重的,難以使用。

6.框架

Spring可以將簡單的組件配置、組合成為複雜的應用。在Spring中,應用對象被聲明式地組合,典型地是在一個XML文件裡。Spring也提供了很多基礎功能(事務管理、持久化框架集成等等),將應用邏輯的開發留給了你。

所有Spring的這些特徵使你能夠編寫更乾淨、更可管理、並且更易於測試的代碼。它們也為Spring中的各種模塊提供了基礎支持。

91. 解釋一下什麼是 aop?

AOP(Aspect-Oriented Programming,面向方面編程),可以說是OOP(Object-Oriented Programing,面向對象編程)的補充和完善。OOP引入封裝、繼承和多態性等概念來建立一種對象層次結構,用以模擬公共行為的一個集合。當我們需要為分散的對象引入公共行為的時候,OOP則顯得無能為力。也就是說,OOP允許你定義從上到下的關係,但並不適合定義從左到右的關係。例如日誌功能。日誌代碼往往水平地散佈在所有對象層次中,而與它所散佈到的對象的核心功能毫無關係。對於其他類型的代碼,如安全性、異常處理和透明的持續性也是如此。這種散佈在各處的無關的代碼被稱為橫切(cross-cutting)代碼,在OOP設計中,它導致了大量代碼的重複,而不利於各個模塊的重用。

而AOP技術則恰恰相反,它利用一種稱為“橫切”的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行為封裝到一個可重用模塊,並將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重複代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。AOP代表的是一個橫向的關係,如果說“對象”是一個空心的圓柱體,其中封裝的是對象的屬性和行為;那麼面向方面編程的方法,就彷彿一把利刃,將這些空心圓柱體剖開,以獲得其內部的消息。而剖開的切面,也就是所謂的“方面”了。然後它又以巧奪天功的妙手將這些剖開的切面復原,不留痕跡。

使用“橫切”技術,AOP把軟件系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處都基本相似。比如權限認證、日誌、事務處理。Aop 的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。正如Avanade公司的高級方案構架師Adam Magee所說,AOP的核心思想就是“將應用程序中的商業邏輯同對其提供支持的通用服務進行分離。”

92. 解釋一下什麼是 ioc?

IOC是Inversion of Control的縮寫,多數書籍翻譯成“控制反轉”。

1996年,Michael Mattson在一篇有關探討面向對象框架的文章中,首先提出了IOC 這個概念。對於面向對象設計及編程的基本思想,前面我們已經講了很多了,不再贅述,簡單來說就是把複雜系統分解成相互合作的對象,這些對象類通過封裝以後,內部實現對外部是透明的,從而降低了解決問題的複雜度,而且可以靈活地被重用和擴展。

IOC理論提出的觀點大體是這樣的:藉助於“第三方”實現具有依賴關係的對象之間的解耦。如下圖:

Java 最常見的 208 道面試題:第九模塊和第十模塊答案

圖 IOC解耦過程

大家看到了吧,由於引進了中間位置的“第三方”,也就是IOC容器,使得A、B、C、D這4個對象沒有了耦合關係,齒輪之間的傳動全部依靠“第三方”了,全部對象的控制權全部上繳給“第三方”IOC容器,所以,IOC容器成了整個系統的關鍵核心,它起到了一種類似“粘合劑”的作用,把系統中的所有對象粘合在一起發揮作用,如果沒有這個“粘合劑”,對象與對象之間會彼此失去聯繫,這就是有人把IOC容器比喻成“粘合劑”的由來。

我們再來做個試驗:把上圖中間的IOC容器拿掉,然後再來看看這套系統:

Java 最常見的 208 道面試題:第九模塊和第十模塊答案

圖 拿掉IOC容器後的系統

我們現在看到的畫面,就是我們要實現整個系統所需要完成的全部內容。這時候,A、B、C、D這4個對象之間已經沒有了耦合關係,彼此毫無聯繫,這樣的話,當你在實現A的時候,根本無須再去考慮B、C和D了,對象之間的依賴關係已經降低到了最低程度。所以,如果真能實現IOC容器,對於系統開發而言,這將是一件多麼美好的事情,參與開發的每一成員只要實現自己的類就可以了,跟別人沒有任何關係!

我們再來看看,控制反轉(IOC)到底為什麼要起這麼個名字?我們來對比一下:

軟件系統在沒有引入IOC容器之前,如圖1所示,對象A依賴於對象B,那麼對象A在初始化或者運行到某一點的時候,自己必須主動去創建對象B或者使用已經創建的對象B。無論是創建還是使用對象B,控制權都在自己手上。

軟件系統在引入IOC容器之後,這種情形就完全改變了,如圖3所示,由於IOC容器的加入,對象A與對象B之間失去了直接聯繫,所以,當對象A運行到需要對象B的時候,IOC容器會主動創建一個對象B注入到對象A需要的地方。

通過前後的對比,我們不難看出來:對象A獲得依賴對象B的過程,由主動行為變為了被動行為,控制權顛倒過來了,這就是“控制反轉”這個名稱的由來。

93. spring 有哪些主要模塊?

Spring框架至今已集成了20多個模塊。這些模塊主要被分如下圖所示的核心容器、數據訪問/集成,、Web、AOP(面向切面編程)、工具、消息和測試模塊。

Java 最常見的 208 道面試題:第九模塊和第十模塊答案


更多信息:howtodoinjava.com/java-spring-framework-tutorials/

94. spring 常用的注入方式有哪些?

Spring通過DI(依賴注入)實現IOC(控制反轉),常用的注入方式主要有三種:

  1. 構造方法注入
  2. setter注入
  3. 基於註解的注入


95. spring 中的 bean 是線程安全的嗎?

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

96. spring 支持幾種 bean 的作用域?

當通過spring容器創建一個Bean實例時,不僅可以完成Bean實例的實例化,還可以為Bean指定特定的作用域。Spring支持如下5種作用域:

  • singleton:單例模式,在整個Spring IoC容器中,使用singleton定義的Bean將只有一個實例
  • prototype:原型模式,每次通過容器的getBean方法獲取prototype定義的Bean時,都將產生一個新的Bean實例
  • request:對於每次HTTP請求,使用request定義的Bean都將產生一個新實例,即每次HTTP請求將會產生不同的Bean實例。只有在Web應用中使用Spring時,該作用域才有效
  • session:對於每次HTTP Session,使用session定義的Bean豆漿產生一個新實例。同樣只有在Web應用中使用Spring時,該作用域才有效
  • globalsession:每個全局的HTTP Session,使用session定義的Bean都將產生一個新實例。典型情況下,僅在使用portlet context的時候有效。同樣只有在Web應用中使用Spring時,該作用域才有效


其中比較常用的是singleton和prototype兩種作用域。對於singleton作用域的Bean,每次請求該Bean都將獲得相同的實例。容器負責跟蹤Bean實例的狀態,負責維護Bean實例的生命週期行為;如果一個Bean被設置成prototype作用域,程序每次請求該id的Bean,Spring都會新建一個Bean實例,然後返回給程序。在這種情況下,Spring容器僅僅使用new 關鍵字創建Bean實例,一旦創建成功,容器不在跟蹤實例,也不會維護Bean實例的狀態。

如果不指定Bean的作用域,Spring默認使用singleton作用域。Java在創建Java實例時,需要進行內存申請;銷燬實例時,需要完成垃圾回收,這些工作都會導致系統開銷的增加。因此,prototype作用域Bean的創建、銷燬代價比較大。而singleton作用域的Bean實例一旦創建成功,可以重複使用。因此,除非必要,否則儘量避免將Bean被設置成prototype作用域。

97. spring 自動裝配 bean 有哪些方式?

Spring容器負責創建應用程序中的bean同時通過ID來協調這些對象之間的關係。作為開發人員,我們需要告訴Spring要創建哪些bean並且如何將其裝配到一起。

spring中bean裝配有兩種方式:

  • 隱式的bean發現機制和自動裝配
  • 在java代碼或者XML中進行顯示配置


當然這些方式也可以配合使用。

98. spring 事務實現方式有哪些?

  1. 編程式事務管理對基於 POJO 的應用來說是唯一選擇。我們需要在代碼中調用beginTransaction()、commit()、rollback()等事務管理相關的方法,這就是編程式事務管理。
  2. 基於 TransactionProxyFactoryBean 的聲明式事務管理
  3. 基於 @Transactional 的聲明式事務管理
  4. 基於 Aspectj AOP 配置事務


99. 說一下 spring 的事務隔離?

事務隔離級別指的是一個事務對數據的修改與另一個並行的事務的隔離程度,當多個事務同時訪問相同數據時,如果沒有采取必要的隔離機制,就可能發生以下問題:

  • 髒讀:一個事務讀到另一個事務未提交的更新數據。
  • 幻讀:例如第一個事務對一個表中的數據進行了修改,比如這種修改涉及到表中的“全部數據行”。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入“一行新數據”。那麼,以後就會發生操作第一個事務的用戶發現表中還存在沒有修改的數據行,就好象發生了幻覺一樣。
  • 不可重複讀:比方說在同一個事務中先後執行兩條一模一樣的select語句,期間在此次事務中沒有執行過任何DDL語句,但先後得到的結果不一致,這就是不可重複讀。


100. 說一下 spring mvc 運行流程?

Spring MVC運行流程圖:

Java 最常見的 208 道面試題:第九模塊和第十模塊答案


Spring運行流程描述:

1. 用戶向服務器發送請求,請求被Spring 前端控制Servelt DispatcherServlet捕獲;

2. DispatcherServlet對請求URL進行解析,得到請求資源標識符(URI)。然後根據該URI,調用HandlerMapping獲得該Handler配置的所有相關的對象(包括Handler對象以及Handler對象對應的攔截器),最後以HandlerExecutionChain對象的形式返回;

3. DispatcherServlet 根據獲得的Handler,選擇一個合適的HandlerAdapter;(附註:如果成功獲得HandlerAdapter後,此時將開始執行攔截器的preHandler(...)方法)

4. 提取Request中的模型數據,填充Handler入參,開始執行Handler(Controller)。 在填充Handler的入參過程中,根據你的配置,Spring將幫你做一些額外的工作:

  • HttpMessageConveter: 將請求消息(如Json、xml等數據)轉換成一個對象,將對象轉換為指定的響應信息
  • 數據轉換:對請求消息進行數據轉換。如String轉換成Integer、Double等
  • 數據根式化:對請求消息進行數據格式化。 如將字符串轉換成格式化數字或格式化日期等
  • 數據驗證: 驗證數據的有效性(長度、格式等),驗證結果存儲到BindingResult或Error中


5. Handler執行完成後,向DispatcherServlet 返回一個ModelAndView對象;

6. 根據返回的ModelAndView,選擇一個適合的ViewResolver(必須是已經註冊到Spring容器中的ViewResolver)返回給DispatcherServlet ;

7. ViewResolver 結合Model和View,來渲染視圖;

8. 將渲染結果返回給客戶端。

101. spring mvc 有哪些組件?

Spring MVC的核心組件:

  1. DispatcherServlet:中央控制器,把請求給轉發到具體的控制類
  2. Controller:具體處理請求的控制器
  3. HandlerMapping:映射處理器,負責映射中央處理器轉發給controller時的映射策略
  4. ModelAndView:服務層返回的數據和視圖層的封裝類
  5. ViewResolver:視圖解析器,解析具體的視圖
  6. Interceptors :攔截器,負責攔截我們定義的請求然後做處理工作


102. @RequestMapping 的作用是什麼?

RequestMapping是一個用來處理請求地址映射的註解,可用於類或方法上。用於類上,表示類中的所有響應請求的方法都是以該地址作為父路徑。

RequestMapping註解有六個屬性,下面我們把她分成三類進行說明。

value, method:

  • value:指定請求的實際地址,指定的地址可以是URI Template 模式(後面將會說明);
  • method:指定請求的method類型, GET、POST、PUT、DELETE等;


consumes,produces

  • consumes:指定處理請求的提交內容類型(Content-Type),例如application/json, text/html;
  • produces:指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回;


params,headers

  • params: 指定request中必須包含某些參數值是,才讓該方法處理。
  • headers:指定request中必須包含某些指定的header值,才能讓該方法處理請求。


06


(完)


分享到:


相關文章: