无招胜有招之spring _高频面试题
1、使用 Spring 框架的好處是什么?
1. 輕量:Spring 是輕量的,基本的版本大約 2MB。
2. 控制反轉:Spring 通過控制反轉實現了松散耦合,對象們給出它們的依賴,而不是創建或查找依賴的對象們。
3. 面向切面的編程(AOP):Spring 支持面向切面的編程,并且把應用業務邏輯和系統服務分開。
4. 容器:Spring 包含并管理應用中對象的生命周期和配置。
5. MVC框架:Spring 的 Web 框架是個精心設計的框架,是 Web 框架的一個很好的替代品。
6. 事務管理:Spring 提供一個持續的事務管理接口,可以擴展到上至本地事務下至全局事務(JTA)。
7. 異常處理:Spring 提供方便的 API 把具體技術相關的異常(比如由 JDBC,Hibernate or JDO 拋出的)轉化為一致的 unchecked 異常。
2、解釋下什么是 AOP?
AOP(Aspect-Oriented Programming,面向方面編程),可以說是 OOP(Object-Oriented Programing,面向對象編程)的補充和完善。OOP 引入封裝、繼承和多態性等概念來建立一種對象層次結構,用以模擬公共行為的一個集合。當我們需要為分散的對象引入公共行為的時候,OOP 則顯得無能為力。也就是說,OOP 允許你定義從上到下的關系,但并不適合定義從左到右的關系。例如日志功能。日志代碼往往水平地散布在所有對象層次中,而與它所散布到的對象的核心功能毫無關系。對于其他類型的代碼,如:安全性、異常處理和透明的持續性也是如此。這種散布在各處的無關的代碼被稱為橫切(cross-cutting)代碼,在 OOP 設計中,它導致了大量代碼的重復,而不利于各個模塊的重用。
而 AOP 技術則恰恰相反,它利用一種稱為“橫切”的技術,剖解開封裝的對象內部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,并將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便于減少系統的重復代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護性。AOP 代表的是一個橫向的關系,如果說“對象”是一個空心的圓柱體,其中封裝的是對象的屬性和行為;那么面向方面編程的方法,就仿佛一把利刃,將這些空心圓柱體剖開,以獲得其內部的消息。而剖開的切面,也就是所謂的“方面”了。然后它又以巧奪天功的妙手將這些剖開的切面復原,不留痕跡。
使用“橫切”技術,AOP 把軟件系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關系不大的部分是橫切關注點。橫切關注點的一個特點是,它們經常發生在核心關注點的多處,而各處都基本相似。比如:權限認證、日志、事務處理。AOP 的作用在于分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。
3、AOP 的代理有哪幾種方式?
AOP 思想的實現一般都是基于代理模式 ,在 Java?中一般采用 JDK 動態代理模式,但是我們都知道,JDK 動態代理模式只能代理接口而不能代理類。因此,Spring AOP 會按照下面兩種情況進行切換,因為 Spring AOP 同時支持 CGLIB、ASPECTJ、JDK 動態代理。
1. 如果目標對象的實現類實現了接口,Spring AOP 將會采用 JDK 動態代理來生成 AOP 代理類;
2. 如果目標對象的實現類沒有實現接口,Spring AOP 將會采用 CGLIB 來生成 AOP 代理類。不過這個選擇過程對開發者完全透明、開發者也無需關心。
4、怎么實現 JDK 動態代理?
JDK 動態代理最核心的一個接口和方法如下所示:
-
?1. java.lang.reflect 包中的 InvocationHandler 接口:
對于被代理的類的操作都會由該接口中的 invoke 方法實現,其中的參數的含義分別是:
1. proxy:被代理的類的實例;
2. method:調用被代理的類的方法;
3. args:該方法需要的參數。
使用方法首先是需要實現該接口,并且我們可以在 invoke 方法中調用被代理類的方法并獲得返回值,自然也可以在調用該方法的前后去做一些額外的事情,從而實現動態代理。
-
2. java.lang.reflect 包中的 Proxy 類中的 newProxyInstance 方法:
其中的參數含義如下:
1. loader:被代理的類的類加載器;
2. interfaces:被代理類的接口數組;
3. invocationHandler:調用處理器類的對象實例。
該方法會返回一個被修改過的類的實例,從而可以自由的調用該實例的方法。
5、AOP 的基本概念:切面、連接點、切入點等?
1. 切面(Aspect):官方的抽象定義為“一個關注點的模塊化,這個關注點可能會橫切多個對象”。
2. 連接點(Joinpoint):程序執行過程中的某一行為。
3. 通知(Advice):“切面”對于某個“連接點”所產生的動作。
4. 切入點(Pointcut):匹配連接點的斷言,在 AOP 中通知和一個切入點表達式關聯。
5. 目標對象(Target Object):被一個或者多個切面所通知的對象。
6. AOP 代理(AOP Proxy):在 Spring AOP 中有兩種代理方式,JDK 動態代理和 CGLIB 代理。
6、通知類型(Advice)型(Advice)有哪些?
1.?前置通知(Before advice):在某連接點(JoinPoint)之前執行的通知,但這個通知不能阻止連接點前的執行。ApplicationContext 中在 <aop:aspect> 里面使用 <aop:before> 元素進行聲明;
2.?后置通知(After advice):當某連接點退出的時候執行的通知(不論是正常返回還是異常退出)。ApplicationContext 中在 <aop:aspect> 里面使用 <aop:after> 元素進行聲明。
3.?返回后通知(After return advice :在某連接點正常完成后執行的通知,不包括拋出異常的情況。ApplicationContext 中在 <aop:aspect> 里面使用 <<after-returning>> 元素進行聲明。
4.?環繞通知(Around advice):包圍一個連接點的通知,類似 Web 中 Servlet規范中的 Filter 的 doFilter 方法。可以在方法的調用前后完成自定義的行為,也可以選擇不執行。ApplicationContext 中在 <aop:aspect> 里面使用 <aop:around> 元素進行聲明。
5.?拋出異常后通知(After throwing advice):在方法拋出異常退出時執行的通知。ApplicationContext 中在 <aop:aspect> 里面使用 <aop:after-throwing> 元素進行聲明。
7、談談你對 IOC 的理解?
?IOC 是 Inversion of Control 的縮寫,多數書籍翻譯成“控制反轉”。簡單來說就是把復雜系統分解成相互合作的對象,這些對象類通過封裝以后,內部實現對外部是透明的,從而降低了解決問題的復雜度,而且可以靈活地被重用和擴展。IOC 理論提出的觀點大體是這樣的:借助于“第三方”實現具有依賴關系的對象之間的解耦。如下圖:
由于引進了中間位置的“第三方”,也就是 IOC 容器,使得 A、B、C、D 這 4 個對象沒有了耦合關系,齒輪之間的傳動全部依靠“第三方”了,全部對象的控制權全部上繳給“第三方”IOC 容器,所以,IOC 容器成了整個系統的關鍵核心,它起到了一種類似“粘合劑”的作用,把系統中的所有對象粘合在一起發揮作用,如果沒有這個“粘合劑”,對象與對象之間會彼此失去聯系,這就是有人把 IOC 容器比喻成“粘合劑”的由來。
把上圖中間的 IOC 容器拿掉,然后再來看看這套系統:
現在看到的畫面,就是我們要實現整個系統所需要完成的全部內容。這時候,A、B、C、D 這 4 個對象之間已經沒有了耦合關系,彼此毫無聯系,這樣的話,當你在實現 A 的時候,根本無須再去考慮 B、C 和 D了,對象之間的依賴關系已經降低到了最低程度。所以,如果真能實現 IOC 容器,對于系統開發而言,這將是一件多么美好的事情,參與開發的每一成員只要實現自己的類就可以了,跟別人沒有任何關系!
我們再來看看,控制反轉(IOC)到底為什么要起這么個名字?我們來對比一下:
軟件系統在沒有引入 IOC 容器之前,對象 A 依賴于對象 B,那么對象 A 在初始化或者運行到某一點的時候,自己必須主動去創建對象 B 或者使用已經創建的對象 B。無論是創建還是使用對象 B,控制權都在自己手上。
軟件系統在引入 IOC 容器之后,這種情形就完全改變了,由于 IOC 容器的加入,對象 A 與對象 B 之間失去了直接聯系,所以,當對象 A 運行到需要對象 B 的時候,IOC 容器會主動創建一個對象 B 注入到對象 A 需要的地方。
通過前后的對比,我們不難看出來:對象 A 獲得依賴對象 B 的過程,由主動行為變為了被動行為,控制權顛倒過來了,這就是“控制反轉”這個名稱的由來。
總的來說:
?IOC:就是由 Spring IOC 容器來負責對象的生命周期和對象之間的關系。
IOC其思想是反轉資源獲取的方向。類的對象創建及對象之間的關系從代碼中移植到配置文件中,由Spring配置文件(即:IOC容器)負責對象的創建及對象之間關系的管理。
8、Bean 的生命周期?
在傳統的 Java 應用中,bean 的生命周期很簡單,使用 Java 關鍵字 new 進行 Bean 的實例化,然后該 Bean 就能夠使用了。一旦 Bean 不再被使用,則由 Java 自動進行垃圾回收。
相比之下,Spring 管理 Bean 的生命周期就復雜多了,正確理解 Bean 的生命周期非常重要,因為 Spring 對 Bean 的管理可擴展性非常強,下面展示了一個 Bean 的構造過程:
?
1. Spring 啟動,查找并加載需要被 Spring 管理的 Bean,進行 Bean 的實例化;
2. Bean 實例化后,對 Bean 的引入和值注入到 Bean 的屬性中;
3. 如果 Bean 實現了 BeanNameAware 接口的話,Spring 將 Bean 的 Id 傳遞給 setBeanName() 方法;
4. 如果 Bean 實現了 BeanFactoryAware 接口的話,Spring 將調用 setBeanFactory() 方法,將 BeanFactory 容器實例傳入;
5. 如果 Bean 實現了 ApplicationContextAware 接口的話,Spring 將調用 Bean 的 setApplicationContext() 方法,將 Bean 所在應用上下文引用傳入進來;
6. 如果 Bean 實現了 BeanPostProcessor 接口,Spring 就將調用它們的 postProcessBeforeInitialization() 方法;
7. 如果 Bean 實現了 InitializingBean 接口,Spring 將調用它們的 afterPropertiesSet() 方法。類似地,如果 Bean 使用 init-method 聲明了初始化方法,該方法也會被調用;
8. 如果 Bean 實現了 BeanPostProcessor 接口,Spring 就將調用它們的 postProcessAfterInitialization() 方法;
9. 此時,Bean 已經準備就緒,可以被應用程序使用了。它們將一直駐留在應用上下文中,直到應用上下文被銷毀;
10. 如果 Bean 實現了 DisposableBean 接口,Spring 將調用它的 destory() 接口方法,同樣,如果 Bean 使用了 destory-method 聲明銷毀方法,該方法也會被調用。
9、Bean 的作用域?
1. singleton : 唯一 bean 實例,Spring 中的 bean 默認都是單例的;
2. prototype : 每次請求都會創建一個新的 bean 實例;
3. request:每一次 HTTP 請求都會產生一個新的 bean,該 bean 僅在當前 HTTP request 內有效;
4. session : 每一次 HTTP 請求都會產生一個新的 bean,該 bean 僅在當前 HTTP session 內有效;
5. global-session:全局 session 作用域,僅僅在基于 portlet 的 web 應用中才有意義,Spring5 已經沒有了。Portlet 是能夠生成語義代碼(例如:HTML)片段的小型 Java Web 插件。它們基于 portlet 容器,可以像 servlet 一樣處理 HTTP 請求。但是,與 servlet 不同,每個 portlet 都有不同的會話。
10、Spring 中的單例 Bean 的線程安全問題了解嗎?
大部分時候我們并沒有在系統中使用多線程,所以很少有人會關注這個問題。單例 bean 存在線程問題,主要是因為:當多個線程操作同一個對象的時候,對這個對象的非靜態成員變量的寫操作會存在線程安全問題。常見的有兩種解決辦法:
1. 在 Bean 對象中盡量避免定義可變的成員變量(不太現實)。
2. 在類中定義一個 ThreadLocal 成員變量,將需要的可變成員變量保存在 ThreadLocal 中(推薦的一種方式)。
11、談談你對 Spring 中的事物的理解?
事務是邏輯上的一組操作,要么都執行,要么都不執行。
-
事務特性
原子性:事務是最小的執行單位,不允許分割。事務的原子性確保動作要么全部完成,要么完全不起作用;
一致性:執行事務前后,數據保持一致;
隔離性:并發訪問數據庫時,一個用戶的事物不被其他事物所干擾,各并發事務之間數據庫是獨立的;
持久性: 一個事務被提交之后。它對數據庫中數據的改變是持久的,即使數據庫發生故障也不應該對其有任何影響。
-
Spring 事務管理接口
1. PlatformTransactionManager:(平臺)事務管理器;
2. TransactionDefinition:事務定義信息(事務隔離級別、傳播行為、超時、只讀、回滾規則);
3. TransactionStatus:事務運行狀態;
所謂事務管理,其實就是“按照給定的事務規則來執行提交或者回滾操作”。
12、Spring 中的事務隔離級別?
TransactionDefinition 接口中定義了五個表示隔離級別的常量:
TransactionDefinition.ISOLATION_DEFAULT:使用后端數據庫默認的隔離級別,MySQL 默認采用的 REPEATABLE_READ 隔離級別 Oracle 默認采用的 READ_COMMITTED 隔離級別;
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致臟讀、幻讀或不可重復讀;
TransactionDefinition.ISOLATION_READ_COMMITTED:允許讀取并發事務已經提交的數據,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生;
TransactionDefinition.ISOLATION_REPEATABLE_READ:對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生;
TransactionDefinition.ISOLATION_SERIALIZABLE:最高的隔離級別,完全服從 ACID 的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。
13、Spring 中的事物傳播行為?
事務傳播行為是為了解決業務層方法之間互相調用的事務問題。當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播。例如:方法可能繼續在現有事務中運行,也可能開啟一個新事務,并在自己的事務中運行。在 TransactionDefinition 定義中包括了如下幾個表示傳播行為的常量:
-
支持當前事務的情況:
TransactionDefinition.PROPAGATION_REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務;
TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行;
TransactionDefinition.PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。
-
不支持當前事務的情況:
TransactionDefinition.PROPAGATION_REQUIRES_NEW:創建一個新的事務,如果當前存在事務,則把當前事務掛起;
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式運行,如果當前存在事務,則把當前事務掛起。
TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行,如果當前存在事務,則拋出異常。
-
其他情況:
TransactionDefinition.PROPAGATION_NESTED:如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價于 TransactionDefinition.PROPAGATION_REQUIRED。
14、Spring 常用的注入方式有哪些?
1. 構造器依賴注入:構造器依賴注入通過容器觸發一個類的構造器來實現的,該類有一系列參數,每個參數代表一個對其他類的依賴。
2. Setter 方法注入:Setter 方法注入是容器通過調用無參構造器或無參 static 工廠方法實例化 bean 之后,調用該 bean 的 Setter 方法,即實現了基于 Setter 的依賴注入。
3. 基于注解的注入:最好的解決方案是用構造器參數實現強制依賴,Setter 方法實現可選依賴。
15、Spring 框架中用到了哪些設計模式?
1. 工廠設計模式 : Spring 使用工廠模式通過 BeanFactory、ApplicationContext 創建 bean 對象;
2. 代理設計模式 : Spring AOP 功能的實現;
3. 單例設計模式 : Spring 中的 Bean 默認都是單例的;
4. 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 結尾的對數據庫操作的類,它們就使用到了模板模式;
5. 包裝器設計模式 : 我們的項目需要連接多個數據庫,而且不同的客戶在每次訪問中根據需要會去訪問不同的數據庫。這種模式讓我們可以根據客戶的需求能夠動態切換不同的數據源;
6. 觀察者模式:Spring 事件驅動模型就是觀察者模式很經典的一個應用;
7. 適配器模式:Spring AOP 的增強或通知(Advice)使用到了適配器模式、SpringMVC 中也是用到了適配器模式適配 Controller。
16、ApplicationContext 通常的實現有哪些?
1. FileSystemXmlApplicationContext:此容器從一個 XML 文件中加載beans 的定義,XML Bean 配置文件的全路徑名必須提供給它的構造函數。
2. ClassPathXmlApplicationContext:此容器也從一個 XML 文件中加載beans 的定義,這里,你需要正確設置 classpath 因為這個容器將在 classpath 里找 bean 配置。
3. WebXmlApplicationContext:此容器加載一個 XML 文件,此文件定義了一個 Web 應用的所有 bean。
總結
以上是生活随笔為你收集整理的无招胜有招之spring _高频面试题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot _全局异常@Res
- 下一篇: springMVC——SSM整合(IDE