總結Spring框架的15個經典面試題。前端
什麼是Spring框架?java
Spring是一種輕量級框架,旨在提升開發人員的開發效率以及系統的可維護性。程序員
咱們通常說的Spring框架就是Spring Framework,它是不少模塊的集合,使用這些模塊能夠很方便地協助咱們進行開發。這些模塊是核心容器、數據訪問/集成、Web、AOP(面向切面編程)、工具、消息和測試模塊。好比Core Container中的Core組件是Spring全部組件的核心,Beans組件和Context組件是實現IOC和DI的基礎,AOP組件用來實現面向切面編程。面試
Spring官網(https://spring.io/)列出的Spring的6個特徵:spring
核心技術:依賴注入(DI),AOP,事件(Events),資源,i18n,驗證,數據綁定,類型轉換,SpEL。sql
測試:模擬對象,TestContext框架,Spring MVC測試,WebTestClient。數據庫
數據訪問:事務,DAO支持,JDBC,ORM,編組XML。編程
Web支持:Spring MVC和Spring WebFlux Web框架。後端
集成:遠程處理,JMS,JCA,JMX,電子郵件,任務,調度,緩存。設計模式
語言:Kotlin,Groovy,動態語言。
列舉一些重要的Spring模塊?
下圖對應的是Spring 4.x的版本,目前最新的5.x版本中Web模塊的Portlet組件已經被廢棄掉,同時增長了用於異步響應式處理的WebFlux組件。
Spring Core:基礎,能夠說Spring其餘全部的功能都依賴於該類庫。主要提供IOC和DI功能。
Spring Aspects:該模塊爲與AspectJ的集成提供支持。
Spring AOP:提供面向方面的編程實現。
Spring JDBC:Java數據庫鏈接。
Spring JMS:Java消息服務。
Spring ORM:用於支持Hibernate等ORM工具。
Spring Web:爲建立Web應用程序提供支持。
Spring Test:提供了對JUnit和TestNG測試的支持。
談談本身對於Spring IOC和AOP的理解
IOC
IOC(Inversion Of Controll,控制反轉)是一種設計思想,就是將本來在程序中手動建立對象的控制權,交由給Spring框架來管理。IOC在其餘語言中也有應用,並不是Spring特有。IOC容器是Spring用來實現IOC的載體,IOC容器實際上就是一個Map(key, value),Map中存放的是各類對象。
將對象之間的相互依賴關係交給IOC容器來管理,並由IOC容器完成對象的注入。這樣能夠很大程度上簡化應用的開發,把應用從複雜的依賴關係中解放出來。IOC容器就像是一個工廠同樣,當咱們須要建立一個對象的時候,只須要配置好配置文件/註解便可,徹底不用考慮對象是如何被建立出來的。在實際項目中一個Service類可能由幾百甚至上千個類做爲它的底層,假如咱們須要實例化這個Service,可能要每次都搞清楚這個Service全部底層類的構造函數,這可能會把人逼瘋。若是利用IOC的話,你只須要配置好,而後在須要的地方引用就好了,大大增長了項目的可維護性且下降了開發難度。
Spring時代咱們通常經過XML文件來配置Bean,後來開發人員以爲用XML文件來配置不太好,因而Sprng Boot註解配置就慢慢開始流行起來。
上圖是Spring IOC的初始化過程,IOC的源碼閱讀:https://javadoop.com/post/spring-ioc。
AOP
AOP(Aspect-Oriented Programming,面向切面編程)可以將那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任(例如事務處理、日誌管理、權限控制等)封裝起來,便於減小系統的重複代碼,下降模塊間的耦合度,並有利於將來的可擴展性和可維護性。
Spring AOP是基於動態代理的,若是要代理的對象實現了某個接口,那麼Spring AOP就會使用JDK動態代理去建立代理對象;而對於沒有實現接口的對象,就沒法使用JDK動態代理,轉而使用CGlib動態代理生成一個被代理對象的子類來做爲代理。
固然也可使用AspectJ,Spring AOP中已經集成了AspectJ,AspectJ應該算得上是Java生態系統中最完整的AOP框架了。使用AOP以後咱們能夠把一些通用功能抽象出來,在須要用到的地方直接使用便可,這樣能夠大大簡化代碼量。咱們須要增長新功能也方便,提升了系統的擴展性。日誌功能、事務管理和權限管理等場景都用到了AOP。
Spring AOP和AspectJ AOP有什麼區別?
Spring AOP是屬於運行時加強,而AspectJ是編譯時加強。Spring AOP基於代理(Proxying),而AspectJ基於字節碼操做(Bytecode Manipulation)。
Spring AOP已經集成了AspectJ,AspectJ應該算得上是Java生態系統中最完整的AOP框架了。AspectJ相比於Spring AOP功能更增強大,可是Spring AOP相對來講更簡單。
若是咱們的切面比較少,那麼二者性能差別不大。可是,當切面太多的話,最好選擇AspectJ,它比SpringAOP快不少。
Spring中的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都有不一樣的會話。
Spring中的單例bean的線程安全問題了解嗎?
大部分時候咱們並無在系統中使用多線程,因此不多有人會關注這個問題。單例bean存在線程問題,主要是由於當多個線程操做同一個對象的時候,對這個對象的非靜態成員變量的寫操做會存在線程安全問題。
有兩種常見的解決方案:
1.在bean對象中儘可能避免定義可變的成員變量(不太現實)。
2.在類中定義一個ThreadLocal成員變量,將須要的可變成員變量保存在ThreadLocal中(推薦的一種方式)。
Spring中的bean生命週期?
1.Bean容器找到配置文件中Spring Bean的定義。
2.Bean容器利用Java Reflection API建立一個Bean的實例。
3.若是涉及到一些屬性值,利用set()方法設置一些屬性值。
4.若是Bean實現了BeanNameAware接口,調用setBeanName()方法,傳入Bean的名字。
5.若是Bean實現了BeanClassLoaderAware接口,調用setBeanClassLoader()方法,傳入ClassLoader對象的實例。
6.若是Bean實現了BeanFactoryAware接口,調用setBeanClassFacotory()方法,傳入ClassLoader對象的實例。
7.與上面的相似,若是實現了其餘*Aware接口,就調用相應的方法。
8.若是有和加載這個Bean的Spring容器相關的BeanPostProcessor對象,執行postProcessBeforeInitialization()方法。
9.若是Bean實現了InitializingBean接口,執行afeterPropertiesSet()方法。
10.若是Bean在配置文件中的定義包含init-method屬性,執行指定的方法。
11.若是有和加載這個Bean的Spring容器相關的BeanPostProcess對象,執行postProcessAfterInitialization()方法。
12.當要銷燬Bean的時候,若是Bean實現了DisposableBean接口,執行destroy()方法。
13.當要銷燬Bean的時候,若是Bean在配置文件中的定義包含destroy-method屬性,執行指定的方法。
說說本身對於Spring MVC的瞭解?
談到這個問題,咱們不得不提提以前Model1和Model2這兩個沒有Spring MVC的時代。
Model1時代:不少學Java比較晚的後端程序員可能並無接觸過Model1模式下的JavaWeb應用開發。在Model1模式下,整個Web應用幾乎所有用JSP頁面組成,只用少許的JavaBean來處理數據庫鏈接,訪問等操做。這個模式下JSP便是控制層又是表現層。顯而易見,這種模式存在不少問題。好比將控制邏輯和表現邏輯混雜在一塊兒,致使代碼重用率極低;又好比前端和後端相互依賴,難以進行測試而且開發效率極低。
Model2時代:學過Servlet並作過相關Demo的朋友應該瞭解Java Bean(Model)+JSP(View)+Servlet(Controller)這種開發模式,這就是早期的Java Web MVC開發模式。Model是系統中涉及的數據,也就是dao和bean;View是用來展現模型中的數據,只是用來展現;Controller是將用戶請求都發送給Servlet作處理,返回數據給JSP並展現給用戶。
Model2模式下還存在不少問題,Model2的抽象和封裝程度還遠遠不夠,使用Model2進行開發時不可避免地會重複造輪子,這就大大下降了程序的可維護性和可複用性。因而不少Java Web開發相關的MVC框架應運而生,好比Struts2,可是因爲Struts2比較笨重,隨着Spring輕量級開發框架的流行,Spring生態圈出現了Spring MVC框架。Spring MVC是當前最優秀的MVC框架,相比於Struts2,Spring MVC使用更加簡單和方便,開發效率更高,而且Spring MVC運行速度更快。
MVC是一種設計模式,Spring MVC是一款很優秀的MVC框架。Spring MVC能夠幫助咱們進行更簡潔的Web層的開發,而且它天生與Spring框架集成。Spring MVC下咱們通常把後端項目分爲Service層(處理業務)、Dao層(數據庫操做)、Entity層(實體類)、Controller層(控制層,返回數據給前臺頁面)。
Spring MVC的簡單原理圖以下:
Spring MVC的工做原理了解嘛?
流程說明:
1.客戶端(瀏覽器)發送請求,直接請求到DispatcherServlet。
2.DispatcherServlet根據請求信息調用HandlerMapping,解析請求對應的Handler。
3.解析到對應的Handler(也就是咱們日常說的Controller控制器)。
4.HandlerAdapter會根據Handler來調用真正的處理器來處理請求和執行相對應的業務邏輯。
5.處理器處理完業務後,會返回一個ModelAndView對象,Model是返回的數據對象,View是邏輯上的View。
6.ViewResolver會根據邏輯View去查找實際的View。
7.DispatcherServlet把返回的Model傳給View(視圖渲染)。
8.把View返回給請求者(瀏覽器)。
Spring框架中用到了哪些設計模式
1.工廠設計模式:Spring使用工廠模式經過BeanFactory和ApplicationContext建立bean對象。
2.代理設計模式:Spring AOP功能的實現。
3.單例設計模式:Spring中的bean默認都是單例的。
4.模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以Template結尾的對數據庫操做的類,它們就使用到了模板模式。
5.包裝器設計模式:咱們的項目須要鏈接多個數據庫,並且不一樣的客戶在每次訪問中根據須要會去訪問不一樣的數據庫。這種模式讓咱們能夠根據客戶的需求可以動態切換不一樣的數據源。
6.觀察者模式:Spring事件驅動模型就是觀察者模式很經典的一個應用。
7.適配器模式:Spring AOP的加強或通知(Advice)使用到了適配器模式、Spring MVC中也是用到了適配器模式適配Controller。
。。。
@Component和@Bean的區別是什麼
1.做用對象不一樣:@Component註解做用於類,而@Bean註解做用於方法。
2.@Component註解一般是經過類路徑掃描來自動偵測以及自動裝配到Spring容器中(咱們可使用@ComponentScan註解定義要掃描的路徑)。@Bean註解一般是在標有該註解的方法中定義產生這個bean,告訴Spring這是某個類的實例,當我須要用它的時候還給我。
3.@Bean註解比@Component註解的自定義性更強,並且不少地方只能經過@Bean註解來註冊bean。好比當引用第三方庫的類須要裝配到Spring容器的時候,就只能經過@Bean註解來實現。
@Bean註解的使用示例:
@Configuration public class AppConfig { @Bean public TransferService transferService() { return new TransferServiceImpl(); } }
上面的代碼至關於下面的XML配置:
<beans> <bean id="transferService" class="com.yanggb.TransferServiceImpl"/> </beans>
下面這個例子是沒法經過@Component註解實現的:
@Bean public OneService getService(status) { case (status) { when 1: return new serviceImpl1(); when 2: return new serviceImpl2(); when 3: return new serviceImpl3(); } }
將一個類聲明爲Spring的bean的註解有哪些?
咱們通常使用@Autowired註解去自動裝配bean。而想要把一個類標識爲能夠用@Autowired註解自動裝配的bean,能夠採用如下的註解實現:
1.@Component註解。通用的註解,可標註任意類爲Spring組件。若是一個Bean不知道屬於哪個層,可使用@Component註解標註。
2.@Repository註解。對應持久層,即Dao層,主要用於數據庫相關操做。
3.@Service註解。對應服務層,即Service層,主要涉及一些複雜的邏輯,須要用到Dao層(注入)。
4.@Controller註解。對應Spring MVC的控制層,即Controller層,主要用於接受用戶請求並調用Service層的方法返回數據給前端頁面。
Spring事務管理的方式有幾種?
1.編程式事務:在代碼中硬編碼(不推薦使用)。
2.聲明式事務:在配置文件中配置(推薦使用),分爲基於XML的聲明式事務和基於註解的聲明式事務。
Spring事務中的隔離級別有哪幾種?
在TransactionDefinition接口中定義了五個表示隔離級別的常量:
ISOLATION_DEFAULT:使用後端數據庫默認的隔離級別,Mysql默認採用的REPEATABLE_READ隔離級別;Oracle默認採用的READ_COMMITTED隔離級別。
ISOLATION_READ_UNCOMMITTED:最低的隔離級別,容許讀取還沒有提交的數據變動,可能會致使髒讀、幻讀或不可重複讀。
ISOLATION_READ_COMMITTED:容許讀取併發事務已經提交的數據,能夠阻止髒讀,可是幻讀或不可重複讀仍有可能發生
ISOLATION_REPEATABLE_READ:對同一字段的屢次讀取結果都是一致的,除非數據是被自己事務本身所修改,能夠阻止髒讀和不可重複讀,但幻讀仍有可能發生。
ISOLATION_SERIALIZABLE:最高的隔離級別,徹底服從ACID的隔離級別。全部的事務依次逐個執行,這樣事務之間就徹底不可能產生干擾,也就是說,該級別能夠防止髒讀、不可重複讀以及幻讀。可是這將嚴重影響程序的性能。一般狀況下也不會用到該級別。
Spring事務中有哪幾種事務傳播行爲?
在TransactionDefinition接口中定義了八個表示事務傳播行爲的常量。
支持當前事務的狀況:
PROPAGATION_REQUIRED: 若是當前存在事務,則加入該事務;若是當前沒有事務,則建立一個新的事務。
PROPAGATION_SUPPORTS: 若是當前存在事務,則加入該事務;若是當前沒有事務,則以非事務的方式繼續運行。
PROPAGATION_MANDATORY: 若是當前存在事務,則加入該事務;若是當前沒有事務,則拋出異常。(mandatory:強制性)。
不支持當前事務的狀況:
PROPAGATION_REQUIRES_NEW: 建立一個新的事務,若是當前存在事務,則把當前事務掛起。
PROPAGATION_NOT_SUPPORTED: 以非事務方式運行,若是當前存在事務,則把當前事務掛起。
PROPAGATION_NEVER: 以非事務方式運行,若是當前存在事務,則拋出異常。
其餘狀況:
PROPAGATION_NESTED: 若是當前存在事務,則建立一個事務做爲當前事務的嵌套事務來運行;若是當前沒有事務,則該取值等價於PROPAGATION_REQUIRED。
"人生老是在一個個漩渦中反覆,你覺得已經從一個漩渦逃離,其實另一個漩渦就在你的腳下。用力蹬一腳,就進去了。"