制作公司網(wǎng)站在公賬匯款時用途備注什么北京seo工程師
一、常見的 ORM 框架有哪些?
1.Mybatis
Mybatis 是一種典型的半自動的 ORM 框架,所謂的半自動,是因?yàn)檫€需要手動的寫 SQL 語句,再由框架根據(jù) SQL 及 傳入數(shù)據(jù)來組裝為要執(zhí)行的 SQL 。其優(yōu)點(diǎn)為:
1. 因?yàn)橛沙绦騿T自己寫 SQL ,相對來說學(xué)習(xí)門檻更低,更容易入門。2. 更方便做 SQL 的性能優(yōu)化及維護(hù)。3. 對關(guān)系型數(shù)據(jù)庫的模型要求不高,這樣在做數(shù)據(jù)庫模型調(diào)整時,影響不會太大。適合軟件需求變更比較頻繁的系統(tǒng),因此國內(nèi)系統(tǒng)大部分都是使用如 Mybatis 這樣的半自動 ORM 框架。
其缺陷為:
不能跨數(shù)據(jù)庫,因?yàn)閷懙?/span> SQL 可能存在某數(shù)據(jù)庫特有的語法或關(guān)鍵詞
2.Hibernate
Hibernate 是一種典型的全自動 ORM 框架,所謂的全自動,是 SQL 語句都不用在編寫,基于框架的 API,可以將對象自動的組裝為要執(zhí)行的 SQL 語句。其優(yōu)點(diǎn)為:
1. 全自動 ORM 框架,自動的組裝為 SQL 語句。2. 可以跨數(shù)據(jù)庫,框架提供了多套主流數(shù)據(jù)庫的 SQL 生成規(guī)則。
其缺點(diǎn)為:
學(xué)習(xí)門檻更高,要學(xué)習(xí)框架 API 與 SQL 之間的轉(zhuǎn)換關(guān)系對數(shù)據(jù)庫模型依賴非常大,在軟件需求變更頻繁的系統(tǒng)中,會導(dǎo)致非常難以調(diào)整及維護(hù)??赡軘?shù)據(jù)庫中隨便改一個表或字段的定義,Java 代碼中要修改幾十處。很難定位問題,也很難進(jìn)行性能優(yōu)化:需要精通框架,對數(shù)據(jù)庫模型設(shè)計也非常熟悉。
二、Bean容器/Ioc容器的理解
Spring 容器主要是對 IoC 設(shè)計模式的實(shí)現(xiàn),主要是使用容器來統(tǒng)一管理 Bean 對象,及管理對象之間的依賴關(guān)系。
創(chuàng)建容器的 API 主要是 BeanFactory 和 ApplicationContext 兩種:
1. BeanFactory 是最底層的容器接口,只提供了最基礎(chǔ)的容器功能: Bean 的實(shí)例化和依賴注入,并且使用懶加載的方式,這意味著 beans 只有在我們通過 getBean() 方法直接調(diào)用它們時才進(jìn)行實(shí)例化。2. ApplicationContext (應(yīng)用上下文)是 BeanFactory 的子接口,與 BeanFactory 懶加載的方式不同,它是預(yù)加載,所以,每一個 bean 都在 ApplicationContext 啟動之后實(shí)例化。3. 除了基礎(chǔ)功能,還添加了很多增強(qiáng):
- 整合了Bean的生命周期管理
- i18n國際化功能(MessageSource)
- 載入多個(有繼承關(guān)系)上下文 ,使得每一個上下文都專注于一個特定的層次,比如應(yīng)用的 web層
- 事件發(fā)布響應(yīng)機(jī)制(ApplicationEventPublisher)
- AOP
三、IoC/DI的理解
概念
IoC (Inversion of Control) 即控制反轉(zhuǎn),是面向?qū)ο缶幊讨械囊环N設(shè)計原則。主要是通過第三方 IoC 容器,對Bean 對象進(jìn)行統(tǒng)一管理,及組織對象之間的依賴關(guān)系。獲得依賴對象的過程,由原本程序自己控制,變?yōu)榱薎oC 容器來主動注入,控制權(quán)發(fā)生了反轉(zhuǎn),所以叫做 IoC ,控制反轉(zhuǎn)。
IoC 又叫做 DI :由于控制反轉(zhuǎn)概念比較含糊(可能只是理解為容器控制對象這一個層面,很難讓人想到誰來維護(hù)對象關(guān)系),相對 IoC 而言,依賴注入實(shí)際上給出了實(shí)現(xiàn) IoC 的方法:注入。所謂依賴注入,就是由 IoC 容器在運(yùn)行期間,動態(tài)地將某種依賴關(guān)系注入到對象之中。
依賴注入 (DI) 和控制反轉(zhuǎn) (IoC) 是從不同的角度的描述的同一件事情,就是指通過引入 IoC 容器,利用依賴關(guān)系注入的方式,實(shí)現(xiàn)對象之間的解耦。
實(shí)現(xiàn)方式
DI 是 IoC 的實(shí)現(xiàn)方式之一。而 DI 的實(shí)現(xiàn)方式主要有兩種:構(gòu)造方法注入和屬性 Setter 注入。
實(shí)現(xiàn)原理
主要依賴反射及 ASM 字節(jié)碼框架實(shí)現(xiàn)(字節(jié)碼框架操作字節(jié)碼更為高效,功能更強(qiáng)大)。
四、Spring中的單例bean的線程安全問題
大部分時候我們并沒有在系統(tǒng)中使用多線程,所以很少有人會關(guān)注這個問題。單例 bean 存在線程問題,主要是因?yàn)楫?dāng)多個線程操作同一個對象的時候,對這個對象的非靜態(tài)成員變量的寫操作會存在線程安全問題。
有兩種常見的解決方案:
1. 在 bean 對象中盡量避免定義可變的成員變量(不太現(xiàn)實(shí))。2. 在類中定義一個 ThreadLocal 成員變量,將需要的可變成員變量保存在 ThreadLocal 中(推薦的一種方式)。
五、Spring中的bean的作用域有哪些?
1.singleton :唯一 bean 實(shí)例, Spring 中的 bean 默認(rèn)都是單例的。2.prototype :每次請求都會創(chuàng)建一個新的 bean 實(shí)例。3.request :每一次 HTTP 請求都會產(chǎn)生一個新的 bean ,該 bean 僅在當(dāng)前 HTTP request 內(nèi)有效。4.session :每一次 HTTP 請求都會產(chǎn)生一個新的 bean ,該 bean 僅在當(dāng)前 HTTP session 內(nèi)有效。5.application :在一個應(yīng)用的 Servlet 上下文生命周期中,產(chǎn)生一個新的 bean6.websocket :在一個 WebSocket 生命周期中,產(chǎn)生一個新的 Bean
六、FactoryBean和BeanFactory
BeanFactory 是 Spring 容器的頂級接口,所有 Bean 對象都是通過 BeanFactory 也就是 Bean 容器來進(jìn)行管理
FactoryBean是實(shí)例化一個 Bean 對象的工廠類,實(shí)現(xiàn)了 FactoryBean<T> 接口的 Bean ,根據(jù)該 Bean 的 ID從 BeanFactory 中獲取的實(shí)際上是 FactoryBean 中 getObject() 方法返回的對象,而不是
FactoryBean 本身,如果要獲取 FactoryBean 對象,請在 id 前面加一個 & 符號來獲取。
七、Bean的生命周期
1. 實(shí)例化 Bean :通過反射調(diào)用構(gòu)造方法實(shí)例化對象。2. 依賴注入:裝配 Bean 的屬性3. 實(shí)現(xiàn)了 Aware 接口的 Bean ,執(zhí)行接口方法:如順序執(zhí)行 BeanNameAware 、 BeanFactoryAware 、 ApplicationContextAware的接口方法。4. Bean 對象初始化前,循環(huán)調(diào)用實(shí)現(xiàn)了 BeanPostProcessor 接口的預(yù)初始化方法 (postProcessBeforeInitialization )5. 執(zhí)行 Bean 對象初始化方法6. Bean 對象初始化后,循環(huán)調(diào)用實(shí)現(xiàn)了 BeanPostProcessor 接口的后初始化方法( postProcessAfterInitialization )7. 容器關(guān)閉時,執(zhí)行 Bean 對象的銷毀方法
八、Spring三級緩存的理解
這個問題或者換個問法: Spring 是如何解決循環(huán)依賴的?答案即是 Spring 的三級緩存
什么是循環(huán)依賴
簡單說,就是 A 對象依賴 B 對象, B 對象又依賴 A 對象,類似的代碼如下:
@Component
public class A{
@Autowired
private B b;
}
@Component
public class B{
@Autowired
private A a;
}
其他還有很多種方式,如 A 依賴 B , B 依賴 C , C 依賴 A ,或是 A 依賴 A 自己,只要產(chǎn)生了依賴關(guān)系的閉環(huán), 即造成了循環(huán)依賴。
那么,循環(huán)依賴會引發(fā)什么問題呢?理解這個問題先得理解 Bean 的生命周期,以下先回顧下
Bean的生命周期回顧
1. 啟動容器:加載 Bean2. 實(shí)例化 Bean 對象3. 依賴注入:裝配 Bean 的屬性4. 初始化 Bean :執(zhí)行 aware 接口方法、預(yù)初始化方法、初始化方法、后初始化方法5. 關(guān)閉容器:銷毀 Bean
在以上第四個步驟執(zhí)行完畢,才算一個初始化完成的 Bean ,也即 Spring 容器中完整的 Bean 對象。

循環(huán)依賴的問題
Spring 容器保存 Bean 的方式,是采取緩存的方式:使用 Map<String, Object> 的結(jié)構(gòu), key 為 Bean
的名稱, value 為 Bean 對象。需要使用時直接從緩存獲取。
假如 A 、 B 互相依賴(循環(huán)依賴):
1. 容器中沒有 A 對象,實(shí)例化 A 對象2. 裝配 A 中的 B 對象,發(fā)現(xiàn) B 在容器中沒有,需要先實(shí)例化 B3. 實(shí)例化 B 對象4. 裝配 B 中的 A 對象,發(fā)現(xiàn) A 在容器中沒有,需要先實(shí)例化 A5. 重復(fù)第一個步驟
這就套娃了 , 你猜是先 StackOverflow 還是 OutOfMemory ?
Spring 怕你不好猜,就先拋出了 BeanCurrentlyInCreationException

[PS]
- Bean會依賴某些注入的Bean來完成初始化工作
- 由于Spring支持構(gòu)造方法注入,屬性/Setter注入的方式,所以不能簡單的先把所有對象全部實(shí)例化,放到緩存中,再全部執(zhí)行初始化。原因很簡單,此時所有對象的引用都可以獲取到,但屬性都是null,執(zhí)行初始化甚至構(gòu)造方法都可能出現(xiàn)空指針異常。
那么我們說 Spring 能解決循環(huán)依賴,也不是所有的情況都可以解決,只有以下情況才支持。
Spring支持的循環(huán)依賴
在 Spring 容器中注冊循環(huán)依賴的 Bean ,必須是單例模式,且依賴注入的方式為屬性注入。
原型模式及構(gòu)造方法注入的方式,不支持循環(huán)依賴。以下為說明:
- 原型模式(prototype)的Bean:原因很好理解,創(chuàng)建新的A時,發(fā)現(xiàn)要注入原型字段B,又創(chuàng)建新的B發(fā)現(xiàn)要注入原型字段A... 還是典型的套娃行為...
- 基于構(gòu)造器的循環(huán)依賴,就更不用說了,官方文檔都攤牌了,你想讓構(gòu)造器注入支持循環(huán)依賴,是不存在的,不如把代碼改了。
那么默認(rèn)單例的屬性注入場景, Spring 是如何支持循環(huán)依賴的?
Spring解決循環(huán)依賴
Spring 是使用三級緩存的機(jī)制來解決循環(huán)依賴問題,以下為三級緩存的定義:

?三級緩存的源碼見 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);
}
以下是部分說明:
- 三級緩存singletonFactories中保存的是ObjectFactory對象(Bean工廠),其中包含了 BeanName,Bean對象,RootBeanDefinition,該工廠可以生成Bean對象。
- 由于Bean可能被代理,此時注入到其他Bean屬性中的也應(yīng)該是代理Bean。
單例模式的 A 、 B 循環(huán)依賴執(zhí)行流程如下:

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