一、常見的 ORM 框架有哪些?
1.Mybatis
1. 因?yàn)橛沙绦騿T自己寫 SQL ,相對(duì)來說學(xué)習(xí)門檻更低,更容易入門。2. 更方便做 SQL 的性能優(yōu)化及維護(hù)。3. 對(duì)關(guān)系型數(shù)據(jù)庫的模型要求不高,這樣在做數(shù)據(jù)庫模型調(diào)整時(shí),影響不會(huì)太大。適合軟件需求變更比較頻繁的系統(tǒng),因此國內(nèi)系統(tǒng)大部分都是使用如 Mybatis 這樣的半自動(dòng) ORM 框架。
不能跨數(shù)據(jù)庫,因?yàn)閷懙?/span> SQL 可能存在某數(shù)據(jù)庫特有的語法或關(guān)鍵詞
2.Hibernate
1. 全自動(dòng) ORM 框架,自動(dòng)的組裝為 SQL 語句。2. 可以跨數(shù)據(jù)庫,框架提供了多套主流數(shù)據(jù)庫的 SQL 生成規(guī)則。
學(xué)習(xí)門檻更高,要學(xué)習(xí)框架 API 與 SQL 之間的轉(zhuǎn)換關(guān)系對(duì)數(shù)據(jù)庫模型依賴非常大,在軟件需求變更頻繁的系統(tǒng)中,會(huì)導(dǎo)致非常難以調(diào)整及維護(hù)??赡軘?shù)據(jù)庫中隨便改一個(gè)表或字段的定義,Java 代碼中要修改幾十處。很難定位問題,也很難進(jìn)行性能優(yōu)化:需要精通框架,對(duì)數(shù)據(jù)庫模型設(shè)計(jì)也非常熟悉。
二、Bean容器/Ioc容器的理解
1. BeanFactory 是最底層的容器接口,只提供了最基礎(chǔ)的容器功能: Bean 的實(shí)例化和依賴注入,并且使用懶加載的方式,這意味著 beans 只有在我們通過 getBean() 方法直接調(diào)用它們時(shí)才進(jìn)行實(shí)例化。2. ApplicationContext (應(yīng)用上下文)是 BeanFactory 的子接口,與 BeanFactory 懶加載的方式不同,它是預(yù)加載,所以,每一個(gè) bean 都在 ApplicationContext 啟動(dòng)之后實(shí)例化。3. 除了基礎(chǔ)功能,還添加了很多增強(qiáng):
- 整合了Bean的生命周期管理
- i18n國際化功能(MessageSource)
- 載入多個(gè)(有繼承關(guān)系)上下文 ,使得每一個(gè)上下文都專注于一個(gè)特定的層次,比如應(yīng)用的 web層
- 事件發(fā)布響應(yīng)機(jī)制(ApplicationEventPublisher)
- AOP
三、IoC/DI的理解
概念
實(shí)現(xiàn)方式
實(shí)現(xiàn)原理
四、Spring中的單例bean的線程安全問題
1. 在 bean 對(duì)象中盡量避免定義可變的成員變量(不太現(xiàn)實(shí))。2. 在類中定義一個(gè) ThreadLocal 成員變量,將需要的可變成員變量保存在 ThreadLocal 中(推薦的一種方式)。
五、Spring中的bean的作用域有哪些?
1.singleton :唯一 bean 實(shí)例, Spring 中的 bean 默認(rèn)都是單例的。2.prototype :每次請(qǐng)求都會(huì)創(chuàng)建一個(gè)新的 bean 實(shí)例。3.request :每一次 HTTP 請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的 bean ,該 bean 僅在當(dāng)前 HTTP request 內(nèi)有效。4.session :每一次 HTTP 請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的 bean ,該 bean 僅在當(dāng)前 HTTP session 內(nèi)有效。5.application :在一個(gè)應(yīng)用的 Servlet 上下文生命周期中,產(chǎn)生一個(gè)新的 bean6.websocket :在一個(gè) WebSocket 生命周期中,產(chǎn)生一個(gè)新的 Bean
六、FactoryBean和BeanFactory
七、Bean的生命周期
1. 實(shí)例化 Bean :通過反射調(diào)用構(gòu)造方法實(shí)例化對(duì)象。2. 依賴注入:裝配 Bean 的屬性3. 實(shí)現(xiàn)了 Aware 接口的 Bean ,執(zhí)行接口方法:如順序執(zhí)行 BeanNameAware 、 BeanFactoryAware 、 ApplicationContextAware的接口方法。4. Bean 對(duì)象初始化前,循環(huán)調(diào)用實(shí)現(xiàn)了 BeanPostProcessor 接口的預(yù)初始化方法 (postProcessBeforeInitialization )5. 執(zhí)行 Bean 對(duì)象初始化方法6. Bean 對(duì)象初始化后,循環(huán)調(diào)用實(shí)現(xiàn)了 BeanPostProcessor 接口的后初始化方法( postProcessAfterInitialization )7. 容器關(guān)閉時(shí),執(zhí)行 Bean 對(duì)象的銷毀方法
八、Spring三級(jí)緩存的理解
什么是循環(huán)依賴
@Component
public class A{
@Autowired
private B b;
}
@Component
public class B{
@Autowired
private A a;
}
Bean的生命周期回顧
1. 啟動(dòng)容器:加載 Bean2. 實(shí)例化 Bean 對(duì)象3. 依賴注入:裝配 Bean 的屬性4. 初始化 Bean :執(zhí)行 aware 接口方法、預(yù)初始化方法、初始化方法、后初始化方法5. 關(guān)閉容器:銷毀 Bean

循環(huán)依賴的問題
1. 容器中沒有 A 對(duì)象,實(shí)例化 A 對(duì)象2. 裝配 A 中的 B 對(duì)象,發(fā)現(xiàn) B 在容器中沒有,需要先實(shí)例化 B3. 實(shí)例化 B 對(duì)象4. 裝配 B 中的 A 對(duì)象,發(fā)現(xiàn) A 在容器中沒有,需要先實(shí)例化 A5. 重復(fù)第一個(gè)步驟

- Bean會(huì)依賴某些注入的Bean來完成初始化工作
- 由于Spring支持構(gòu)造方法注入,屬性/Setter注入的方式,所以不能簡單的先把所有對(duì)象全部實(shí)例化,放到緩存中,再全部執(zhí)行初始化。原因很簡單,此時(shí)所有對(duì)象的引用都可以獲取到,但屬性都是null,執(zhí)行初始化甚至構(gòu)造方法都可能出現(xiàn)空指針異常。
Spring支持的循環(huán)依賴
- 原型模式(prototype)的Bean:原因很好理解,創(chuàng)建新的A時(shí),發(fā)現(xiàn)要注入原型字段B,又創(chuàng)建新的B發(fā)現(xiàn)要注入原型字段A... 還是典型的套娃行為...
- 基于構(gòu)造器的循環(huán)依賴,就更不用說了,官方文檔都攤牌了,你想讓構(gòu)造器注入支持循環(huán)依賴,是不存在的,不如把代碼改了。
Spring解決循環(huán)依賴

?三級(jí)緩存的源碼見 DefaultSingletonBeanRegistry :
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>
(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new
HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new
ConcurrentHashMap<>(16);
}
- 三級(jí)緩存singletonFactories中保存的是ObjectFactory對(duì)象(Bean工廠),其中包含了 BeanName,Bean對(duì)象,RootBeanDefinition,該工廠可以生成Bean對(duì)象。
- 由于Bean可能被代理,此時(shí)注入到其他Bean屬性中的也應(yīng)該是代理Bean。

為什么要使用三級(jí)緩存
- 普通的IoC容器使用一級(jí)緩存即可,但無法解決循環(huán)依賴問題。
- 解決循環(huán)依賴問題:使用二級(jí)緩存即可。一級(jí)緩存保存完整Bean,二級(jí)緩存保存提前曝光的不完 整的Bean。
- 需要AOP代理Bean時(shí),有兩種實(shí)現(xiàn)思路: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??(1)再加一級(jí)緩存 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (2)只使用二級(jí)緩存,其中二級(jí)緩存保存Bean的代理對(duì)象,代理對(duì)象中引用不完整的原始對(duì)象即可。
- Spring使用三級(jí)緩存保存ObjectFactory即Bean工廠,在代碼的層次設(shè)計(jì)及擴(kuò)展性上都會(huì)更好。 ps:ObjectFactory內(nèi)部可以根據(jù) SmartInstantiationAwareBeanPostProcessor 這樣的后置處 理器獲取提前曝光的對(duì)象。
九、AOP的理解
- JDK動(dòng)態(tài)代理:需要被代理類實(shí)現(xiàn)接口,使用 InvocationHandler 和 Proxy 動(dòng)態(tài)的生成代理類
- CGLIB動(dòng)態(tài)代理:需要被代理類能被繼承,不能被final修飾。使用 MethodInterceptor 來對(duì)方法攔截。CGLIB底層是基于ASM字節(jié)碼框架,在運(yùn)行時(shí)動(dòng)態(tài)生成代理類
- 前置通知 ? ?使用@Before:通知方法會(huì)在目標(biāo)方法調(diào)用之前執(zhí)行。
- 后置通知 ? ?使用@After:通知方法會(huì)在目標(biāo)方法返回或者拋出異常后調(diào)用。
- 返回之后通知 ? ?使用@AfterReturning:通知方法會(huì)在目標(biāo)方法返回后調(diào)用。
- 拋異常后通知 ? ?使用@AfterThrowing:通知方法會(huì)在目標(biāo)方法拋出異常后調(diào)用。
- 環(huán)繞通知 ? ?使用@Around:通知包裹了被通知的方法,在被通知的方法通知之前和調(diào)用之后執(zhí)行自定義的行為。
十、Spring事務(wù)中的隔離級(jí)別有哪幾種?
- ISOLATION_DEFAULT:使用后端數(shù)據(jù)庫默認(rèn)的隔離級(jí)別,Mysql默認(rèn)采用的REPEATABLE_READ 隔離級(jí)別;Oracle默認(rèn)采用的READ_COMMITTED隔離級(jí)別。
- ISOLATION_READ_UNCOMMITTED:最低的隔離級(jí)別,允許讀取尚未提交的數(shù)據(jù)變更,可能會(huì)導(dǎo)致臟讀、幻讀或不可重復(fù)讀。
- ISOLATION_READ_COMMITTED:允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù),可以阻止臟讀,但是幻讀或不可重復(fù)讀仍有可能發(fā)生
- ISOLATION_REPEATABLE_READ:對(duì)同一字段的多次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改,可以阻止臟讀和不可重復(fù)讀,但幻讀仍有可能發(fā)生。
- ISOLATION_SERIALIZABLE:最高的隔離級(jí)別,完全服從ACID的隔離級(jí)別。所有的事務(wù)依次逐個(gè)執(zhí)行,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說,該級(jí)別可以防止臟讀、不可重復(fù)讀以及幻讀。但是這將嚴(yán)重影響程序的性能。通常情況下也不會(huì)用到該級(jí)別。
十一、Spring事務(wù)中有哪幾種事務(wù)傳播行為?
- PROPAGATION_REQUIRED:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。
- PROPAGATION_SUPPORTS: 如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行。
- PROPAGATION_MANDATORY: 如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則拋出異常。(mandatory:強(qiáng)制性)。
- PROPAGATION_REQUIRES_NEW: 創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
- PROPAGATION_NOT_SUPPORTED: 以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
- PROPAGATION_NEVER: 以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常。
- PROPAGATION_NESTED: 如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來運(yùn)行;如果當(dāng)前沒有事務(wù),則該取值等價(jià)于PROPAGATION_REQUIRED。
?12.SpringMVC的流程文章來源:http://www.zghlxwxcb.cn/news/detail-628329.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-628329.html
- 第一步:(發(fā)起)發(fā)起請(qǐng)求到前端控制器(DispatcherServlet)
- 第二步:(查找)前端控制器請(qǐng)求HandlerMapping查找 Handler(可以根據(jù)xml配置、注解進(jìn)行查找)
- 第三步:(返回)處理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping 會(huì)把請(qǐng)求映射為HandlerExecutionChain對(duì)象(包含一個(gè)Handler處理器(頁面控制器)對(duì)象,多個(gè)HandlerInterceptor攔截器對(duì)象),通過這種策略模式,很容易添加新的映射策略
- 第四步:(調(diào)用)前端控制器調(diào)用處理器適配器去執(zhí)行Handler
- 第五步:(執(zhí)行)處理器適配器HandlerAdapter將會(huì)根據(jù)適配的結(jié)果去執(zhí)行Handler
- 第六步:(返回)Handler執(zhí)行完成給適配器返回ModelAndView
- 第七步:(接收)處理器適配器向前端控制器返回ModelAndView (ModelAndView是
- SpringMVC框架的一個(gè)底層對(duì)象,包括 Model和view)
- 第八步:(解析)前端控制器請(qǐng)求視圖解析器去進(jìn)行視圖解析 (根據(jù)邏輯視圖名解析成真正的視圖 (jsp)),通過這種策略很容易更換其他視圖技術(shù),只需要更改視圖解析器即可
- 第九步:(返回)視圖解析器向前端控制器返回View
- 第十步:(渲染)前端控制器進(jìn)行視圖渲染 (視圖渲染將模型數(shù)據(jù)(在ModelAndView對(duì)象中)填充到request域)
- 第十一步:(響應(yīng))前端控制器向用戶響應(yīng)結(jié)果
以下是對(duì)出現(xiàn)的一些組件的介紹:(1) 前端控制器 DispatcherServlet (不需要程序員開發(fā))。作用:接收請(qǐng)求,響應(yīng)結(jié)果,相當(dāng)于轉(zhuǎn)發(fā)器,中央處理器。有了 DispatcherServlet 減少了其它組件之間的耦合度。(2) 處理器映射器 HandlerMapping (不需要程序員開發(fā))。作用:根據(jù)請(qǐng)求的 url 查找 Handler 。(3) 處理器適配器 HandlerAdapter (不需要程序員開發(fā))。作用:按照特定規(guī)則( HandlerAdapter 要求的規(guī)則)去執(zhí)行 Handler 。(4) 處理器 Handler (需要程序員開發(fā))。注意:編寫 Handler 時(shí)按照 HandlerAdapter 的要求去做,這樣適配器才可以去正確執(zhí)行 Handler(5) 視圖解析器 ViewResolver (不需要程序員開發(fā))。作用:進(jìn)行視圖解析,根據(jù)邏輯視圖名解析成真正的視圖( view )(6) 視圖 View (需要程序員開發(fā) jsp )。注意: View 是一個(gè)接口,實(shí)現(xiàn)類支持不同的 View 類型( jsp 、 freemarker 、 pdf… )
十三、Mybatis中,#{}和${}的區(qū)別
- #{變量名} 是預(yù)處理替換的方式,本質(zhì)是 jdbc 中占位符的替換。如傳入字符串,會(huì)替換為帶單引號(hào)的值??梢园踩愿茫?
- ${變量名} 是字符串的替換,只是對(duì) sql 字符串進(jìn)行拼接。如傳入字符串,會(huì)直接替換為字符串的值,不加單引號(hào)。
十四、Mybatis中如何一對(duì)一、一對(duì)多關(guān)聯(lián)
十五、SpringBoot 自動(dòng)配置原理

到了這里,關(guān)于JavaEE 面試常見問題的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!