前言
spring框架部分的題目,是我根據Java Guide的面試突擊版本V3.0再整理出來的,其中,我選擇了一些比較重要的問題,並重新做出相應回答,並添加了一些比較重要的問題,希望對大家起到一定的幫助。
系列文章:
Spring框架
-
什么是 Spring 框架?
Spring是一種輕量級開發框架,旨在提高開發人員的開發效率以及系統的可維護性。我們說的Spring框架是很多模塊的集合,包括核心容器,數據訪問集成,web,AOP等等。
-
@RestController vs @Controller和區別?
單獨使用Controller時,適用於前后端不分離的應用,Controller返回一個model and view。
RestController將返回數據寫入ResponseBody中,Controller+ResponseBody注解一起用和RestController是一樣的功能。
-
簡單說說你對IOC的理解
IOC叫做控制反轉,控制反轉是一種設計思想,簡單來說就是,本來把程序員控制的流程交給框架控制,框架提供給程序員一些擴展點,程序員實現擴展點就可以方便的調用框架做需要的事情。
SpringIoc容器是控制反轉設計思想的一種實現,程序員把管理對象生命周期的工作交給框架來做,通過配置文件或注解配置需要的對象,在使用的時候跟Spring容器要就可以了。
-
談談你對AOP的理解
AOP是面向切面編程,通過把和業務無關,但是卻被很多業務模塊調用的系統功能封裝起來,減少系統的重復代碼,提高代碼的復用性並提高的系統的維護性。
比如實際項目中,中間件組的web層代碼AOP框架規范是我制定的,統一處理異常,記錄日志等操作是放在這個AOP中的,具體用的是ControllerAdvice實現的。
-
AOP的實現原理你了解嗎?簡單說說
AOP的實現最核心的就是利用JDK的動態代理或者cglib實現,項目啟動時通過反射獲取相關的信息,在創建代理對象時,如果被代理對象實現了接口,就是用JDK動態代理,如果沒有實現接口,就使用cglib創建被代理對象的子類來實現代理。
-
Spring的AOP和AspectJ的AOP有什么區別?
二者都是AOP思想的實現,AspectJ的功能更加強大。
-
springAOP是基於運行時動態增強
-
AspectJ是編譯時操作字節碼增強,運行時更快
項目中遇到無法使用Spring來管理對象這種情況時,就會考慮使用AspectJ來增強對象
-
-
為什么需要bean的作用域?
spring容器需要管理對象的生命周期,spring通過scope作用域的概念給使用者對對象生命周期的更精細的控制。
-
bean的作用域都有哪些?
- singleton:單例,會一直存活直到容器關閉,spring默認的對象作用域是單例的
- prototype:多實例,每次請求都會創建一個新的對象,交給使用方以后,spring就不負責管理對象的生命周期了
- request:每次請求都創建一個實例,請求完畢后銷毀對象
- session:每個session創建一個實例,session失效后銷毀對象實例
-
Spring 中的單例 bean 的線程安全問題了解嗎?
對單例bean的非靜態成員變量的讀寫會有線程安全問題。
如果每個線程對成員變量的修改業務上沒有關聯,可以通過使用ThreadLocal來保存每個線程單獨的變量拷貝副本來實現線程安全。
-
@Component 和 @Bean 的區別是什么?
- 作用對象不同:component作用於類,bean作用於方法。
- bean注解適用於引用第三方類庫的bean時使用,因為沒辦法使用component注解用於第三方類庫的源碼
-
將⼀個類聲明為Spring的 bean 的注解有哪些?
- Component:通用注解
- Service:Service層的注解
- Controller:控制層的注解
- Repository:DAO層的注解
-
Spring 中的 bean ⽣命周期?
- Spring先對bean進行實例化
- Spring將值和引用注入到相關屬性中
- 如果bean實現了相關的aware接口,spring就會調用set方法把相關需求的實例注入到bean中
- 如果實現了 beanpostProcessor接口,會調用before方法
- 如果有postConstruct注解,會調用注解的方法
- 如果實現了InitialingBean接口,會調用afterPropertiesSet方法
- 如果指定了init-method,會調用init-method
- 最后調用beanpostProcessor的after方法
- 銷毀前,會調用DispoableBean的destory方法
- 如果指定了destroy-method,調用這個方法
- 最后調用 preConstruct注解修飾的方法
流程圖如下:

-
你知道spring MVC的工作原理嗎?
- DispatcherServlet接收用戶的請求后,根據請求向處理器映射器查詢具體處理器
- 處理器映射器返回對應的處理器鏈返回給dispatherServlet
- dispatcherServlet會將請求發送給具體的處理器,並等待處理
- 處理器處理完畢后,會返回邏輯視圖名和模型給前端控制器
- 前端控制器根據邏輯視圖名向視圖解析器解析具體的視圖
- 最后視圖負責根據模型數據渲染頁面,並返回給客戶端
-
MVC的注解都用過什么?
- RestController:指定控制器
- RequestMapping,負責編寫具體的url,指定post方法,並指定返回內容類型
- RequestBody:接收通過body傳遞過來的JSONObject數據參數
- ControllerAdvice和ExceptionHandler:負責controller的全局異常處理
-
Spring 框架中⽤到了哪些設計模式?
- 單例模式:spring的bean作用域默認是單例的
- 代理模式:AOP就是代理模式的實現
- 工廠模式:applicationContext就是對象工廠
- 觀察者模式:spring的事件機制就是觀察者模式的一個典型應用
-
Spring 管理事務的⽅式有⼏種?
- 編程式事務:硬編碼
- 聲明式事務:
- 基於XML
- 基於注解
-
Spring事務的隔離級別都有哪些,如何設置?
和MySQL中的事務隔離級別一樣,有四種隔離級別可以設置,還有一種是使用數據庫的默認隔離級別
在transactional注解中設置isolation屬性即可
-
Spring中事務的傳播機制有哪些?
事務的傳播機制指的是,如果事務方法互相調用,事務應該如何傳播,具體分為三大類:
- 支持當前事務的:如果有事務,加入當前事務
- 不支持當前事務的:如果有事務,掛起或者拋出異常
- 其他情況:嵌套事務,父事務回滾,子事務也會回滾
我們的具體業務中,相關聯的業務都寫在了同一個service方法中,所以不存在事務的傳播機制問題
如果需要拆分方法,那么需要根據具體業務邏輯具體分析使用哪種事務
-
@Transactional(rollbackFor = Exception.class)注解了解嗎?
了解,如果不這么配置,那么事務只會在運行時異常的時候才會回滾,我們也需要cover到非運行時異常的情況。
-
Spring是如何管理bean的?
Spring會讀取配置文件或者注解定義的bean信息,實例化為一個BeanDefinition,存入到一個List
中,然后利用反射實例化對象,存入一個Map<String,Object>中 -
Bean的生命周期中的擴展點都有哪些?
- Spring實例化
- 依賴注入
- 各種XXAware接口,注入相關實例
- BeanPostProcessor
- InitializingBean
- DisposableBean
-
Spring常見的注入方式有哪些?
- 構造函數
- set方法
- 注解注入
-
Spring是如何解決循環依賴的問題的?
什么是循環依賴?循環依賴分為兩種,一種是構造器依賴,這種JVM會報錯;另一種是屬性依賴。Spring解決的是屬性循環依賴。
Spring是通過遞歸來實例化bean和它依賴的bean的,直到bean中沒有依賴就會返回,然后反遞歸層層設置上屬性。這里有個關鍵點,如果是循環依賴,就會把沒有真實完成的類注入到對應類中。 -
哪幾種情況會引起事務失效?
- this引用方法
- private或者protected
Springboot
-
什么是Springboot?
Springboot簡化了使用Spring的難度,使開發者能快速上手,具體表現在:
- 節省了繁重的配置
- 提供了各種starter啟動器
-
Spring Boot 的核心注解是哪個?它主要由哪幾個注解組成的?
SpringbootApplicaition是Springboot的啟動類注解,也是核心注解,它是由下面三個注解組成的:
- ComponentScan:組件掃描,將組件注冊到容器中
- EnableAutoConfiguration:打開自動配置,根據類路徑中jar包是否存在來決定是否開啟某個默認配置,用exclude可以關閉某個默認配置
- SpringBootConfiguration: 相當於Configuration,是一個配置類,會被ComponentScan注解掃描到
-
什么是 JavaConfig?
JavaConfig是在 Spring 3.0 開始從一個獨立的項目並入到 Spring 中的,通過純Java方法來配置Springg容器,可以避免使用XML。
-
Spring Boot 自動配置原理是什么?
- Springboot啟動的時候會通過@EnableAutoConfiguration注解開啟自動配置,並找到META-INF/spring.factories中的所有自動配置類,並對其進行加載。
- 自動配置類都是以AutoConfiguration結尾的,里面包含一個關鍵性注解EnableConfigurationProperties,這個注解可以把配置了ConfigurationProperties注解的類注入到容器中,這個類可以接收application.properties中配置的配置信息。
-
YML配置文件的優勢在哪里?
yml格式的配置文件有着可讀性更強的樹型結構,但是因為yml配置文件需要過多的考慮格式問題,我們項目組還是使用properties配置文件。
-
Spring Boot 是否可以使用 XML 配置 ?
可以使用,但是Springboot推薦使用java配置。如果一定要使用的話,可以使用@importResource注解引入一個XML配置
-
什么是 Spring Profiles?
我們的環境分為開發驗證和生產環境,沒有profile的概念時,需要手動維護多個配置文件,然后進行替換,使用Profile時,可以定義單個配置文件,並定義名稱為application-dev.properties,application-verify.properties和application-prod.properties,在總配置文件中指定spring.active.profile為對應的配置文件后綴即可。同樣的道理,也可以基於Profile注解實現不同環境注入不同的bean到容器中。
-
如何重新加載 Spring Boot 上的更改,而無需重新啟動服務器?Spring Boot項目如何熱部署?
使用spring-boot-devtools可以實現熱部署,具體操作時,需要在idea中開啟自動build項目選項,並在配置文件中增加熱部署相關的配置項,比如spring.devtools.restart.enabled設置為true。
-
Spring Boot 中的 starter 到底是什么 ?
starter的作用簡單來說有下面兩個:
- 方便引入相關依賴
- 自動配置各模塊需要的屬性,這里的原理和第四個問題,自動配置原理那個問題是一樣的
-
spring-boot-starter-parent 有什么用 ?
這個是springboot工程的父級依賴,我覺得最核心的就是定義了各種版本號,這樣我們在自己的項目中就不需要寫版本號了。其他的功能還有比如默認使用Java8,使用UTF-8編碼等等。
-
不適用spring-boot-starter-parent,如果創建springboot項目?
一般來說,這種場景可能出現在該模塊已經有了一個父模塊存在,無法再引入parent,這種場景下可以在父模塊中使用dependacyManagement來實現引入sprintboot
-
Spring Boot 打成的 jar 和普通的 jar 有什么區別 ?
boot打成的jar不能作為普通的jar被其他項目引用,因為普通可引用的jar解壓后就是包名,而Springboot的jar是放在Boot-INF/classes下的。如果一定要引用,那么也可以在pom文件中增加配置,將springboot打成兩個jar,一個可執行,一個可引用。SpringBoot打包可執行可依賴的jar包
-
運行 Spring Boot 有哪幾種方式?
- 打jar包用java命令或者打war包用容器執行
- main方法直接執行
- maven的插件也可以運行: mvn spring-boot:run
-
讓你寫個starter 你會怎么寫?
- 編寫自己的Properties配置類和需要提供的核心服務類XXService
- 編寫AutoConfig類。
- 通過EnableAutoConfiguration開啟自動配置並且注入Properties類的實例;通過@Bean注冊核心服務類到容器中,構造函數相關參數就是Properties類中提供的
- 通過Condition類控制相關的條件
- 在META-INF/spring.factories文件,里面寫入key為一個特別長的配置,value為AutoConfig類的全路徑名
參考資料
