SSM框架面试题总结
Spring
如何實現一個IOC容器
- 配置文件中指定需要掃描的包路徑
- 定義一些注解,分別表示訪問控制器,業務控制層,數據持久層,依賴注入注解,獲取配置文件注解
- 從配置文件中獲取需要掃描的包路徑,獲取到當前路徑下的文件信息及文件夾信息,我們將當前路徑下所有的以.class結尾的文件添加到一個Set集合中進行存儲
- 遍歷這個Set集合,獲取在類上有指定注解的類,并將其交給IOC容器,定義一個安全的Map來存儲這些對象
- 遍歷這個IOC容器,獲取到每一個類的實例,判斷里面是否有依賴其他類的實例,然后注入
Spring是什么
輕量級的開源的J2EE框架,是一個容器框架,用來裝javabean(java對象),中間層框架(萬能膠)可以起一個連接作用,比如說Mybatis
Spring是一個輕量級的控制反轉(IOC)和面向切面(AOP)的容器框架
- 從大小和開銷兩方面而言Spring都是輕量級的
- 通過控制反轉(IOC)的技術達到松耦合的目的
- 提供了面向切面編程的豐富支持,允許通過分離應用的業務邏輯與系統級服務進行內聚性的開發(日志)
- 包含并管理應用對象(Bean)的配置和生命周期,這個意義上是一個容器
- 將簡單的組件配置,組合稱為復雜的應用,這個意義上是一個框架
談談你對AOP的理解
系統是由許多不同的組件所組成的,每一個組件各負責一塊特定功能,除了實現自身的核心功能之外,這些組件還經常承擔著額外的職責,例如日志,事務管理和安全這樣的核心服務經常融入到自身具有的核心業務邏輯的組件上去,這些系統服務經常被稱為橫切關注點,因為他們會跨越系統的多個組件
當我們需要為分散的對象引入公共行為的時候,OOP則顯得無能為力,也就是說,OOP允許你從上到下的關系,但并不適合定義從左到右的關系,例如日志功能
日志代碼往往水平地散布在所有對象層次中,而與它所散布到的對象的核心功能毫無關系
在OOP設計中,它導致了大量代碼的重復,而不利于各個模塊的重用
AOP:將程序的交叉業務邏輯(比如安全,日志,事務等),封裝成一個切面,然后注入到目標對象(具體業務邏輯)中去,AOP可以對某個對象或某些對象的功能進行增強,比如對象中的方法進行增強,可以在執行某個方法之前額外的做一些事情,在某個方法執行之后額外的做一些事情
Spring如何通過三級緩存解決循環依賴?為什么不能是兩次?
答案鏈接
兩次和三次的主要差別在于AOP時代理對象的創建時機,在Bean的生命周期中,AOP是在調用postProcessAfterInitialization時實現的,如果出現了循環依賴,那沒有辦法,只有給Bean先創建代理,但是沒有出現循環依賴的情況下,設計之初就是讓Bean在生命周期的最后一步完成代理而不是在實例化后就立馬完成代理。
談談你對IOC的理解
容器概念,控制反轉,依賴注入
ioc容器:實際上就是個Map,里面存的是各種對象(xml里配置的bean節點,@repository,@service,@controller,@component),在項目啟動的時候會讀取配置文件里面的bean節點,根據全限定類名使用反射創建對象放到map里,掃描到打上上述注解的類還是通過反射創建對象放到map里
這個時候map里就有各種對象了,接下來我們在代碼里需要用到里面的對象時,再通過DI注入(autowired,resource等注解,xml里bean節點內的ref屬性,項目啟動的時候會讀取xml節點ref屬性根據id注入,也會掃描這些注解,根據類型或id注入,id就是對象名)
控制反轉:
沒有引入IOC容器之前,對象A依賴于對象B,那么對象A在初始化或者運行到某一點的時候,自己必須主動去創建對象B或者使用已經創建的對象B,無論是創建還是使用對象B,控制權都在自己手上.
引入IOC容器之后,對象A和對象B之間失去了直接聯系,當對象A運行到需要對象B的時候,IOC容器會主動創建一個對象B注入到對象A需要的地方
通過前后的對比,不難看出,對象A獲得依賴對象B的過程,由主動行為變成了被動行為,控制權顛倒過來了
全部對象的控制權全部上繳給"第三方"容器,所以,IOC容器成了整個系統的關鍵核心,它起到了一種類似"粘合劑"的作用,把系統中的所有對象粘合在一起
BeanFactory和ApplicationContext有什么區別和聯系
ApplicationContext是BeanFactory的子接口
ApplicationContext提供了更完整的功能
Spring容器初始化實現位置(refresh):AbstractApplicationContext
- BeanFactory采用的是延遲加載形式來注入bean的,即只有在使用到某個bean時(調用getBean()),才對該Bean進行加載實例化,這樣,我們就不能發現一些存在的Spring的配置問題,如果Bean的某一個屬性沒有注入,BeanFactory加載后,直至第一次使用調用getBean方法才拋出異常
- ApplicationContext,它是在容器啟動時,一次性創建了所有的bean.這樣,在容器啟動時,我們就可以發現Spring中存在的配置錯誤,這樣有利于檢查所依賴的屬性是否注入.ApplicationContext啟動后預載入所有的單實例Bean,通過預載入單實例bean,確保當你需要的時候,你就不用等待,因為它們已經創建好了
- 相對于基本的BeanFactory,ApplicationContext唯一的不足是占用內存空間,當應用程序配置Bean較多時,程序啟動較慢
- BeanFactory通常以編程的方式被創建,ApplicationContext還能以聲明的方式創建,如使用ContextLoader
- BeanFactory和ApplicationContext都支持BeanPostProcessor,BeanFactoryPostProcessor的使用,但兩者之間的區別是:BeanFactory需要手動注冊,而ApplicationContext則是自動注冊
描述Spring Bean的生命周期
解釋下Spring支持的幾種bean的作用域
- Singleton:默認,每個容器中只有一個bean的實例,單例的模式由BeanFactory自身來維護,該對象的生命周期是與Spring IOC容器一致(但在第一次被注入時才會創建)
- prototype:為每一個bean請求提供一個實例,在每次注入時都會創建一個新的對象
- request:bean被定義為在每個HTPP請求中創建一個單例對象,也就是說在單個請求中都會復用這一個單例對象
- session:與request范圍類似,確保每個session中有一個bean的實例,在session過期后,bean會隨之失效
- application:bean被定義在ServletContext的生活周期中復用一個單例對象
- websocket:bean被定義為在websocket的生命周期中復用一個單例對象
global-session:全局作用域,global-session和Portlet應用相關.當你的應用部署在Porlet容器中工作時,它包含很多portlet.如果你想要聲明讓所有的portlet共用全局的存儲變量的化,那么這全局變量需要存儲在globla-session中,全局作用域與Servlet中的session作用域效果相同
Spring框架中的單例Bean是線程安全的嗎?
不安全
Spring中的Bean默認是單例模式的,框架并沒有對bean進行多線程的封裝處理
如果Bean是有狀態的,那就需要開發人員自己來進行線程安全的保證,最簡單的方法就是改變bean的作用域,把singleton改為prototype,這樣每次請求bean就相當于是new Bean()
- 有狀態就是有數據存儲功能
- 無狀態就是不會保存數據 Controller Service Dao層本身并不是線程安全的,只是如果只是調用里面的方法,而且多線程調用一個實例的方法,會在內存中復制變量,這是自己的線程的工作內存,是安全的
Dao會操作數據庫Connection,Connection是帶有狀態的,比如說數據庫事務,Spring的事務管理器使用ThreadLocal為不同線程維護了一套獨立的connection副本,保證線程之間不會互相影響(Spring是如何保證事務獲取同一個Connection的)
不要在bean中聲明任何有狀態的實例變量或類變量,如果必須如此,那么就使用ThreadLocal把變量變為線程私有的,如果bean的實例變量或類變量需要在多個線程之間共享,那么就只能使用synchronized,lock,CAS等這些實現線程同步的方法了
Spring中的ThreadLocal
Spring框架中都用到了哪些設計模式
Spring中設計模式
Spring事務的實現方式和原理以及隔離級別
在使用Spring框架時,可以有兩種聲明事務的方式,一種是編程式的,一種是聲明式的,@Transactional注解就是聲明式的
首先,事務這個概念是數據庫層面的,Spring只是基于數據庫中的事務進行了擴展,以及提供了一些能讓程序員更加方便地操作事務的方式,
比如我們可以通過在某個方法上增加@Tansaction注解,就可以開啟事務,這個方法中所有的sql都會在一個事務中執行,統一成功或失敗
在一個方法上加了@Transactional注解后,Spring會基于這個類生成一個代理對象,會將這個代理對象作為bean,當在使用這個代理對象的方法時,如果這個方法上存在@Transaction注解,那么代理邏輯會先把事務的自動提交設置為false,然后再去執行原本的業務邏輯方法,如果執行業務邏輯方法沒有出現異常,那么代理邏輯中就會將事務進行提交,如果執行業務邏輯方法出現了異常,那么則會將事務回滾
當然,針對哪些異常回滾事務是可以配置的,可以利用@Transational注解中的rollbackFor屬性進行配置,默認情況下會將RuntimeException和Error進行回滾
隔離級別同數據庫
Spring默認是read committed,最終以Spring為準,如果Spring級別數據庫不支持,那就取決于數據庫
Spring事務傳播機制
圖解Spring事務傳播機制
多個事務方法相互調用時,事務如何在這些方法間傳播
方法A是一個事務的方法,方法A執行過程中調用了方法B,那么方法B有無事務以及方法B對事務的要求不同都會對方法A的事務具體執行造成影響,同時方法A的事務對方法B的事務執行也會有影響,這種影響具體是聲明就由兩個方法所定義的事務的傳播類型所決定
- REQUIRED(Spring默認的事務傳播類型):如果當前沒有事務,則自己新建一個事務,如果當前存在事務,則加入這個事務
- SUPPORTS:當前存在事務,則加入當前事務,如果當前沒有事務,就以非事務方法執行
- MANDATORY:當前存在事務,則加入當前事務,如果當前事務不存在,則拋出異常
- REQUIRES_NEW:創建一個新事務,如果存在當前事務,則掛起該事務
- NOT_SUPPORTED:以非事務方式執行,如果當前存在事務,則掛起該事務
- NEVER:不使用事務,如果事務存在,則拋出異常
- NESTED:如果當前事務存在,則嵌套事務中執行,否則和REQUIRED的操作一樣(子事務中的異常捕獲后,父事務不回滾)
Spring事務什么時候會失效
Spring事務的原理是AOP,進行了切面增強,那么失效的根本原因是AOP不起作用了!常見情況有如下幾種
什么是bean的自動裝配,有哪些方式
開啟自動裝配,只需要在xml配置文件中定義"autowire"屬性
<bean id = "customer" class="com.xq.Customer" AutoWrie=" "/>五種裝配方式
- no-缺省情況下,自動配置是通過ref屬性手動設定
手動裝配:以value或ref的方式明確指定屬性值都是手動裝配
需要通過"ref"屬性來連接bean
- byName-根據bean的屬性名稱進行自動裝配
- byType-根據bean的屬性名稱進行自動裝配
- constructor-類似byType,不過是應用于構造器的參數,如果一個bean與構造器參數的類型相同,則進行自動裝配
- autodetect-如果有默認的構造器,通過constructor,否則byType
SpringBoot,SpringMVC,Spring
- Spring是一個IOC容器,用來管理Bean,使用依賴注入實現控制反轉,可以很方便的整合各種框架,提供AOP機制彌補OOP代碼重復問題,將不同類不同方法中的共同處理抽取成切面,自動主入給方法執行,比如日志,異常等
- SpringMVC是Spring對web框架的一個解決方案,提供了一個總的前端控制器Servlet,用來接受請求,然后定義了一套路由策略(url到handle的映射)及適配執行handle,將handle結果使用視圖解析技術生成視圖展現給前端
- springboot是spring提供的一個快速開發工具表,簡化配置,整合了一系列解決方案
Spring中后置處理器的作用
Spring中的后置處理器分為BeanFactory后置處理器和Bean后置處理器,它們是Spring底層源碼架構設計中非常重要的一種機制,同時開發者也可以利用這兩種后置處理器來進行擴展.BeanFactory后置處理器標識針對BeanFactory的處理器,Spring啟動過程中,會先創建出BeanFactory的實例,然后利用BeanFactory處理器來加工BeanFactory,比如Spring的掃描就是基于BeanFactory后置處理器來實現的
Bean的后置處理器也類似,Spring在創建一個Bean的過程中,首先會實例化得到一個對象,然后再利用Bean后置處理器來對該實例對象進行加工,比如我們常說的依賴注入和AOP
SpringAOP執行順序
Spring中的5種Aop常見應用方式 - 知乎
Spring4
Around --> Before --> Around(出現異常取消) --> After --> AfterReturning/AfterThrowing
Spring5
Around–>Before–>AfterReturning/AfterThrowing–>After–>Around(出現異常就取消)
SpringMVC
SpringMVC工作流程
SpringMVC的主要組件
根據request找到相應的處理器。因為Handler(Controller)有兩種形式,一種是基于類的Handler,另一種是基于Method的Handler(也就是我們常用的)
調用Handler的適配器,因為SpringMVC中handler可以是任意形式,但是Servlet需要的處理方法結構式固定的。如果把Handler(Controller)當做工具的話,那么HandlerAdapter就相當于干活的工人
對異常的處理
用來將String類型的視圖名和Locale解析為View類型的視圖
有的Handler(Controller)處理完后沒有設置返回類型,比如是void方法,這是就需要從request中獲取viewName
從request中解析出Locale。Locale表示一個區域,比如zh-cn,對不同的區域的用戶,顯示不同的結果,這就是i18n(SpringMVC中有具體的攔截器LocaleChangeInterceptor)
主題解析,這種類似于我們手機更換主題,不同的UI,css等
處理上傳請求,將普通的request封裝成MultipartHttpServletRequest
用于管理FlashMap,FlashMap用于在redirect重定向中傳遞參數
SpringMVC中如何解決POST請求中文亂碼問題,GET的又如何處理呢?
POST : request.setCharacterEncodingFilter(UTF-8)
web.xml配過濾器
GET:
MyBatis
MyBatis的優缺點
優點
缺點
MyBatis與Hibernate有哪些不同
SQL和ORM的爭論,永遠都不會終止
- 開發速度的對比:
Hibernate的真正掌腥要比Mybatis難些。Mybatis框架相對簡單很容易上手,但也相對簡陋些。
比起兩者的開發速度,不僅僅要考慮到兩者的特性及性能,更要根據項目需求去考慮究賁哪一個更適合項目開發,比如:一個項目中用到的復雜查詢基本沒有,就是簡單的增刪改查,這樣選擇hibernate效率就很快了,因為基本的sq|浯句已經被封裝好了,根本不需要你去寫sql浯句,這就節省了大量的時間,但是對于一個大型項目,復雜浯句較多,這樣再去選擇hibernate就不是一個太好的選擇,選擇mybatis就會加快許多,而且句的管理也比較方便。 - 開發工作量的對比:
Hibernate和MyBatis都有相應的代碼生成工具。可以生成簡單基本的DAO層方法。針對高級查詢Mybatis需要手動編寫SQL語句,以及ResultMapo而Hibernate有良好的映射機制,開發者無需關心SQL的生成與結果映射可以更專注于業務流程 - sql優化方面:
Hibernate的查詢會將表中的所有字段查洵出來,這一點會有性能消耗。Hibernate也可以自己寫SQL來指定需要查詢的字段,但這樣就破壞Hibernate開發的簡潔性。而MybatisfiSQL是手動編寫的,所以可以按需求指定查詢的字段。
Hibernate HQL語句的調優需要將SQL打出來,而Hibernate的SQL被很多人嫌棄因為太丑了。MyBatis的SQL是自己手動寫的所以調整方便。但Hibernate具有自己的日志統計。Mybatis本身不帶日志統計,使用Log4j進行日志 - 對象管理的對比:
Hibernate是完整的對象/關系映射解決方案,它提供了對象狀態管理(statemanagement)的功能,使開發者不再需要理會底層數據庫系統的細節。也就是說相對于見的JDBC/SQL持久層方案中需要管理語句,
Hibernate采用了更自然的面向對象的視角來持久化Java應用中的數據。
換句話說,使用Hibernate的開發者應該總是關注對象的狀態(state)不必考慮SQL語句的執行。這部分細節已經由Hibernate掌管妥當,只有開發者在進行系統性能調優的時候才需要進行了解。而MyBatis這一塊沒有文檔說明,用戶需要對對象自己進行詳細的管理。
#{}和${}的區別是什么
簡述Mybatis的插件運行原理,如何編寫一個插件?
Mybatis只支持針對ParameterHandler,ResultSetHandler,StatementHandler,Executor這四種接口的插件,Mybatis使用JDK的動態代理,為需要攔截的接口生成代理對象以實現接口方法的攔截功能,每當執行這四種接口對象的方法時,就會進入攔截方法,具體就是InvocationHandler的invoke()方法,攔截那些你指定需要攔截的方法
編寫插件:
實現Mybatis的Interceptor接口并復寫intercept()方法,然后給插件編寫注解,指定要攔截哪一個接口的哪些方法即可,在配置文件中配置編寫的插件
Mybatis中當實體類中的屬性名和表中的字段名不一樣,怎么辦?
解決方案
SpringBoot
SpringBoot自動配置原理
如何理解SpringBoot中的starter
什么是嵌入式服務器?為什么要使用嵌入式服務器?
SpringBoot內置tomcat.jar
方便
總結
以上是生活随笔為你收集整理的SSM框架面试题总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ansible获取linux信息,ans
- 下一篇: 7-4 统计工龄 (20 分)(C语言实