目錄
一、引言
二、Spring
1.Spring框架的特性
2.介紹一下IOC和AOP
3.IOC和AOP都是如何實現的
4.怎么實現依賴注入
5.為什么AOP不用靜態代理
6.介紹一下反射
7.Spring如何解決循環依賴問題
8.Spring常用注解
9.Spring事務什么情況會失效
10.Bean的生命周期
11.Bean是單例的嗎
三、Spring MVC
1.MVC是什么,介紹一下
2.SpringMVC 處理流程
四、Spring Boot
1.Spring Boot相比于Sprig的優點
2.Spring Boot用了哪些設計模式
3.Spring Boot的約定大于配置
4.Spring Boot的自動裝配原理是什么
5.Spring Boot怎么做到導入就直接使用的
6.攔截器和過濾器的區別
五、MyBatis
1.與傳統的JDBC相比,MyBatis的優勢在哪里
2.MyBatis的特殊功能
3.如何使用MyBatis
4.MyBatis中的#和$的區別是什么
六、總結
一、引言
本篇文章將介紹面試中關于Spring的一些常見問題。
二、Spring
1.Spring框架的特性
1.Ioc容器:Spring通過控制反轉這樣的思想實現了對象的創建和對象之間的依賴關系,用戶只需要定義好Bean和依賴關系,Spring容器負責創建和組裝這些對象。
2.AOP:面向切面編程,用戶在業務邏輯的某個部分進行切面,在這個切面上引入另外的一段代碼進行執行。例如:事務管理,安全控制。
3.事務管理:Spring提供了一套一致的事務管理接口,支持聲明式事務和編程式事務。
4.MVC框架:Spring MVC是一個基于Servlet API構建的Web框架,支持靈活的URL到頁面的映射。
2.介紹一下IOC和AOP
IOC:控制反轉,主要作用是解決了創建對象和依賴管理的高耦合,主要是通過依賴注入(DI)實現的,使用了IOC之后,我們不用再去使用new來創建對象了,而是通過IOC容器實例化對象。簡單的說就是需要什么對象,從這個容器里面取就可以了。
AOP:面向切面編程,將那些與業務代碼無關的,但是許多業務模塊公用的部分封裝起來,降低代碼耦合度,基于動態代理的思想實現。
3.IOC和AOP都是如何實現的
IOC:
1.反射:通過Java的反射機制動態地加載類,實例對象,調用方法等操作,在程序運行的時候,檢查類,方法,屬性等信息,根據想要的內容動態地進行選擇或組裝
2.依賴注入:通過一些方式(構造方法注入,Setter注入,注解字段注入等)將組件之間的依賴屬性管理好,將組件之間的依賴關系定義在注解中或者配置文件中
3.設計模式--工廠模式:采用工廠模式的方式來對對象的創建和使用進行管理,通過工廠模式對Bean的實例化,Bean生命周期進行管理
4.容器實現:通常使用BeanFactory或者ApplicationContext來管理Bean。BeanFactory是Spring容器的最基礎實現,ApplicationContext是BeanFactory的擴展,提供了更多的功能
AOP:
動態代理的思想:AOP需要在不修改目標方法源碼的前提下,再添加另外一套邏輯,這就要求程序在運行的時候,能夠動態生成一個“增強版“的目標對象,這個對象既保留了原方法的業務邏輯,又自動添加了要插入的邏輯。
Spring支持的兩種動態代理:
1.基于JDK實現的動態代理(基于接口的代理):使用Proxy類和InvocationHandler接口實現。這種方式需要代理的類實現一個或多個接口。每一個動態代理類都必須實現InvocationHandler這個接口,每個代理類的實例都會關聯一個handler,當代理對象調用一個方法的時候,這個方法會被轉發為invocationHandler接口的invoke()方法來調用。
2.基于CGLIB的動態代理(基于類的代理):當被代理的類沒有實現接口時,Spring會生成一個CGLIB庫生成一個被代理的子類。
4.怎么實現依賴注入
1.構造方法注入:保證對象初始化時依賴已就緒
2.Setter方法注入:通過Setter方法設置依賴,靈活性高,依賴可能未完全初始化
3.注解注入:不利于進行擴展
5.為什么AOP不用靜態代理
要實現是可以進行實現的,只不過由于
1.代碼爆炸,有100個Service就得寫100個,不好維護
2.僵化:一旦有地方更改了方法名,全部都得更改
3.無法動態篩選:不能指定要為哪個注解加一些邏輯
6.介紹一下反射
反射是指程序在運行的時候,對于任意一個類,都能夠獲取到這個類的屬性和方法,對于任意一個對象,都能夠取調用它的屬性和方法。
特性:
1.運行時類信息訪問
2.動態對象創建:通過Class類的newInstance()方法或Constructor()方法創建動態地創建對象
3.動態方法的調用:包括私有方法,通過Method類的invoke()方法實現
4.訪問和修改字段值:在程序運行的期間,即使是私有的,也能通過Field類的get()和set()方法完成對對象的字段修改
7.Spring如何解決循環依賴問題
Spring只解決了通過Setter方法進行依賴注入且Bean是單例模式下的循環依賴。
通過三級緩存實現
1.一級緩存:存放的是完全初始化好的、可用的Bean實例,getBean()返回的是這里面的Bean(初始化好,依賴已注入,初始化方法已執行)
2.二級緩存:存放的是提前暴露的Bean的原始對象引用,專門用來處理循環依賴,此時的Bean只是被實例化了,但是還沒有進行初始化,初始化方法也沒有得到執行。
3.三級緩存:存放的是Bean的ObjectFactory工廠對象。解決循環依賴的關鍵:Bean被實例化之后,Spring會創建一個ObjectFactory并將其放入三級緩存中,當檢測循環依賴需要注入一個尚未完全初始化的Bean時,就會調用這個工廠來獲取早期引用
Spring通過三級緩存和提前暴露未完全初始化的對象引用來解決其中一個循環依賴問題
舉例:A依賴B,B也依賴于A(A和B都必須是單例的Bean)
1.Spring會先創建A的構造函數進行實例化,之后Spring會將一個特殊的工廠對象存入到第三級緩存中
2.填充A的屬性發現其依賴B,于是就按照1的方法將B的工廠對象也存入到第三級緩存中
3.填充B的時候又發現其依賴于A,在一級緩存,二級緩存中都沒找到A,只有第三級緩存中定位到了A的工廠對象,調用工廠的getObject()方法之后,得到A的早期引用,放入到二級緩存,并清理A的第三級緩存
4.B獲得了所有的依賴后,執行初始化方法,之后將B對象放入到一級緩存,清除其在二、三級緩存的臨時條目
5.回溯完成A的構建
B創建完畢之后,為A進行屬性注入,從二級緩存中獲得Bean,并執行初始化方法,填充到一級緩存中,清除在二級緩存的臨時條目
三級緩存工廠:負責實例化后立刻暴露對象生成能力,兼顧AOP代理的提前生成
二級緩存:臨時存儲已確定的早期引用,避免重復生成代理
一級緩存:最終交付完整的Bean
不能使用二級緩存:
因為要正確處理被AOP代理的Bean,第三季緩存不是直接緩存對象,而是一個工廠去判斷是否需要被代理,如果要,就生成代理對象放入二級緩存,如果不要直接返回原始對象。
三級緩存的本質是:按需延遲生成正確引用。二級緩存缺乏這種動態決策能力。
8.Spring常用注解
1.MVC相關:RestController,RequestMapping,RequestBody,
2.Service層:bean,service,mapper,component,resitory,configuration,autowired
3.AOP相關:aspectJ(找切面)before,after,around,afterthrowing,
4.事務相關:Transacational
9.Spring事務什么情況會失效
1.未捕獲異常:一個事務方法中發生了未捕獲的異常,并且異常未被處理,那么事務會失效,所有數據庫操作都會回滾。
2.某些異常不會被事務檢查
3.多個事務之間存在嵌套,且事務傳播屬性配置不正確也會導致事務失效
4.跨方法調用事務問題:一個事務方法內部調用另外一個方法,而這個被調用方法沒有事務注解,那么可能導致外部的這層事務失效
5.在非public修飾的方法中使用
10.Bean的生命周期
1.實例化:SpringFactory調用getBean方法實例化Bean
2.設置屬性:通過構造方法,Setter方法,注解等方式將屬性注入
三、初始化:3.檢測一些Aware接口(BeanNameAware,BeanFactoryAware,ApplicationContextAware)并設置相關依賴
4.BeanPostProcessor接口的前置處理:調用接口的postBeforeInitialization()方法
5.是否實現了Initialization接口
6.是否配置了自定義的init-method聲明了初始化方法
7.BeanPostProcessor的后置處理,調用postAfterInitialization()方法
8.注冊Destruction相關回調接口
四、銷毀
9.是否實現了DisposableBean接口,調用其destroy()方法。
10.是否配置了自定義的destroy-method聲明銷毀方法
11.Bean是單例的嗎
Spring中Bean默認是單例的,但是可以通過設置scope屬性為prototype來設計成多例。
注意:Spring只會幫我們管理單例的Bean,而不會管理prototype的Bean,多例的Bean,Spring創建好了之后就交給了用戶。
階段 | 單例 | 非單例 |
創建時機 | 容器啟動時創建 | 每次請求時創建實例 |
初始化流程 | 完整執行生命周期流程 | 每次創建實例時才執行生命周期流程(只到初始化) |
銷毀時機 | 容器關閉銷毀 | 用戶進行手動釋放資源 |
內存占用 | 內存占用小,但需考慮線程安全問題 | 內存開銷較大,需手動管理資源釋放 |
使用場景 | 無狀態服務 | 有狀態對象(用戶會話,臨時計算對象) |
三、Spring MVC
1.MVC是什么,介紹一下
M(Model):模型,代表一個存取數據的對象,對對象進行一些核心數據處理
V(View):視圖,為用戶提供使用界面,與用戶直接進行交互
C(Controller):用于將用戶的請求轉發給對應的Model進行處理,并根據用戶的計算結果向用戶提供相應響應
2.SpringMVC 處理流程
這里比較復雜,小編在這里貼一張圖,大家自行觀看吧!
1.用戶發送一個request請求,到達dispatchServlet前置處理器
2.前置處理器從HandlerMapping處理器映射器中查找對應的處理器
3.處理器映射器返回一條執行鏈
4.前置處理器根據執行鏈請求HandlerAdapter適配器執行
5.適配器調用ControllerHandler處理請求
6.ControllerHandler執行完畢之后返回model and view給適配器
7.適配器返回model and view給前置處理器
8.前置處理器將這個發給view resolver解析
9.view resolver返回view
10.將view返回給用戶
四、Spring Boot
1.Spring Boot相比于Sprig的優點
1.Spring Boot提供了自動化配置:根據項目的依賴關系和一些規則來配置應用程序,很多配置都自動完成了,開發者只需要關注業務邏輯
2.Spring Boot提供了快速啟動器:通過引入不同的starter,快速集成了常用的框架和庫(數據庫,消息隊列,Web開發等)
3.Spring Boot默認集成了多種內嵌服務器:無需額外配置,即可將應用打包成JAR包直接部署運行。
2.Spring Boot用了哪些設計模式
1.代理模式:AOP
2.策略模式:JDK和CGLIB兩種代理模式,根據類有沒有實現接口自行去進行選擇
3.裝飾器模式:Spring用Transaction解決緩存和數據庫事務問題對事務的支持
4.單例模式:Spring Boot中的Bean默認是單例的
5.工廠模式
6.適配器模式:MVC中體現,HandlerAdapter
3.Spring Boot的約定大于配置
1.自動化配置:Spring Boot會根據項目自動配置相應的依賴和環境,例如添加了Spring-Boot-starter-web這個依賴就會自動內嵌Tomcat和Spring MVC,無需手動編寫XML文件
2.默認配置:存在許多默認配置:連接數據庫,設置Web服務器等
3.約定的項目結構:Spring Boot提供了一套項目結構,主應用程序類置于根包,控制器類,服務類置于子包
4.Spring Boot的自動裝配原理是什么
關鍵是@EnableAutoConfiguration注解實現,開發者引入了一些依賴之后,這個注解會根據這些依賴自動進行一些配置程序上下文和功能
Spring Boot在啟動的時候回去掃描外部jar包下的spring.factories文件,將文件的配置信息加載到Spring容器中
簡單來說:自動裝配就是通過一些注解或者配置文件通過Spring Boot的幫助下開啟和配置各種功能。
5.Spring Boot怎么做到導入就直接使用的
1.起步依賴:在創建Spring Boot項目的時候就會直接通過maven或gradle依賴,創建的時候就構建了一些操作
2.自動配置:根據EnableAutoConfiguration注解對文件進行掃描,獲取其中的配置程序的上下文和功能
3.條件注解:只有滿足相應的條件才會創建相應的Bean,常見的注解有:ConditionalOnClass等
6.攔截器和過濾器的區別
過濾器:對要進入Servlet容器的請求和響應進行預處理和后處理,通過實現javax.servlet.Filter接口,重寫其中的init,doFilter,destroy方法來執行相應邏輯,按照配置的順序依次經過各個過濾器,然后才會到達servlet,返回結果也是同理,也得經過各個過濾器
攔截器:對控制器的方法進行攔截,通過實現HandlerInterceptor接口的preHandler,postHandler的方法來完成相應的邏輯,當請求到達攔截器,會經過攔截器的preHandle方法,返回true才能繼續執行后續的攔截器或者方法。控制器方法執行完之后,會調用攔截器的postHandle方法,最后在請求處理完成后,調用攔截器的afterCompletion方法。
區別:
所屬規范不同:?一個是Java Servlet規范的一部分,一個是Spring框架提供的機制
執行順序:一個是在進入執行器之前,一個是進入了執行器,在調用執行器方法前后
使用范圍:一個是對所有請求,一個是對Spring MVC控制器的請求進行攔截
功能特性:過濾器主要用于對請求進行預處理,如字符編碼,請求日志記錄等
攔截器主要用于控制器方法的執行,如權限驗證,性能監控等
五、MyBatis
1.與傳統的JDBC相比,MyBatis的優勢在哪里
1.基于SQL語句編程,比較靈活,同時又與應用程序和數據庫分離,極大地解耦合了,便于統一管理,同時支持寫動態的SQL
2.減少了代碼量,不用一直去手動地對數據庫進行開關
3.本質還是JDBC來連接數據庫,所以JDBC支持的,MyBatis都支持
4.提供映射標簽,支持對象和數據庫的ORM字段關系映射,提供對象關系映射標簽
2.MyBatis的特殊功能
1.插件擴展機制:可編寫插件去攔截SQL執行過程,實現分頁、性能監控、SQL改寫的邏輯
2.與Spring生態無縫銜接:通過@MapperScan快速掃描Mapper接口,配置簡潔高效
3.如何使用MyBatis
1.配置MyBatis:配置MyBatis的數據源,SQL映射文件等
2.創建實體類:用于映射數據庫表的實體類
3.編寫SQL映射文件:創建XML文件,定義SQL語句和映射關系
4.編寫DAO接口:創建DAO接口,定義數據庫操作的方法
5.編寫具體的查詢語句:編寫具體語句
4.MyBatis中的#和$的區別是什么
#會預編譯SQL語句,將#{}替換成?,執行SQL的時候給預編譯SQL中的?賦值,可以有效地防止SQL注入這樣的安全問題
$是直接將參數拼接進SQL語句中,參數沒有得到校驗,過濾,可能會出現SQL注入的問題
5.MyBatisPlus和MyBatis的區別
1.代碼生成器:根據表結構自動生成實體類
2.CRUD操作:提供了快捷方法
3.通用方法封裝:封裝了許多方法:條件構造器,排序,分頁查詢等
4.分頁插件:內置了許多插件,用來實現各項功能
5.注解的支持
六、總結
? 本篇文章簡單介紹了一些面試中常見的關于Spring的八股,內容肯定不是很完善,也可能存在錯誤,歡迎大家指正!最后,強調以上大部分內容都來自于:小林coding:Spring面試題 | 小林coding,大家想看更完整的,可以去小林coding官網閱讀,謝謝觀看!