2021-Java后端工程師面試指南-(SSM)

前言

文本已收錄至我的GitHub倉庫贱迟,歡迎Star:https://github.com/bin392328206/six-finger
種一棵樹最好的時間是十年前,其次是現(xiàn)在

Tips

面試指南系列絮供,很多情況下不會去深挖細(xì)節(jié)衣吠,是小六六以被面試者的角色去回顧知識的一種方式琴锭,所以我默認(rèn)大部分的東西禁荒,作為面試官的你,肯定是懂的怠益。

https://www.processon.com/view/link/600ed9e9637689349038b0e4

上面的是腦圖地址

叨絮

SSM框架,這個是我們平時用的最多的忧换,所以面試中也是經(jīng)常被問到恬惯,今天我們就來看看這幾個框架唄

然后下面是前面的文章匯總

什么是Spring

Spring 是一種輕量級開發(fā)框架,旨在提高開發(fā)人員的開發(fā)效率以及系統(tǒng)的可維護(hù)性亚茬。我們一般說 Spring 框架指的都是 Spring Framework酪耳,它是很多模塊的集合,使用這些模塊可以很方便地協(xié)助我們進(jìn)行開發(fā)刹缝。這些模塊是:核心容器碗暗、數(shù)據(jù)訪問/集成,、Web梢夯、AOP(面向切面編程)言疗、工具、消息和測試模塊颂砸。比如:Core Container 中的 Core 組件是Spring 所有組件的核心噪奄,Beans 組件和 Context 組件是實(shí)現(xiàn)IOC和依賴注入的基礎(chǔ),AOP組件用來實(shí)現(xiàn)面向切面編程人乓。

談?wù)勛约簩τ?Spring IoC 和 AOP 的理解

IoC(Inverse of Control:控制反轉(zhuǎn))是一種設(shè)計思想勤篮,就是 將原本在程序中手動創(chuàng)建對象的控制權(quán),交由Spring框架來管理撒蟀。 IoC 在其他語言中也有應(yīng)用叙谨,并非 Spring 特有。 IoC 容器是 Spring 用來實(shí)現(xiàn) IoC 的載體保屯, IoC 容器實(shí)際上就是個Map(key手负,value),Map 中存放的是各種對象。

將對象之間的相互依賴關(guān)系交給 IoC 容器來管理姑尺,并由 IoC 容器完成對象的注入竟终。這樣可以很大程度上簡化應(yīng)用的開發(fā),把應(yīng)用從復(fù)雜的依賴關(guān)系中解放出來切蟋。 IoC 容器就像是一個工廠一樣统捶,當(dāng)我們需要創(chuàng)建一個對象的時候,只需要配置好配置文件/注解即可柄粹,完全不用考慮對象是如何被創(chuàng)建出來的喘鸟。 在實(shí)際項(xiàng)目中一個 Service 類可能有幾百甚至上千個類作為它的底層,假如我們需要實(shí)例化這個 Service驻右,你可能要每次都要搞清這個 Service 所有底層類的構(gòu)造函數(shù)什黑,這可能會把人逼瘋。如果利用 IoC 的話堪夭,你只需要配置好愕把,然后在需要的地方引用就行了拣凹,這大大增加了項(xiàng)目的可維護(hù)性且降低了開發(fā)難度。

AOP(Aspect-Oriented Programming:面向切面編程)能夠?qū)⒛切┡c業(yè)務(wù)無關(guān)恨豁,卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任(例如事務(wù)處理嚣镜、日志管理、權(quán)限控制等)封裝起來橘蜜,便于減少系統(tǒng)的重復(fù)代碼菊匿,降低模塊間的耦合度,并有利于未來的可拓展性和可維護(hù)性计福。

Spring AOP就是基于動態(tài)代理的捧请,如果要代理的對象,實(shí)現(xiàn)了某個接口棒搜,那么Spring AOP會使用JDK Proxy,去創(chuàng)建代理對象活箕,而對于沒有實(shí)現(xiàn)接口的對象力麸,就無法使用 JDK Proxy 去進(jìn)行代理了,這時候Spring AOP會使用Cglib 育韩,這時候Spring AOP會使用 Cglib 生成一個被代理對象的子類來作為代理.

一般我們可以使用 AspectJ ,Spring AOP 已經(jīng)集成了AspectJ 克蚂,AspectJ 應(yīng)該算的上是 Java 生態(tài)系統(tǒng)中最完整的 AOP 框架了。

使用 AOP 之后我們可以把一些通用功能抽象出來筋讨,在需要用到的地方直接使用即可埃叭,這樣大大簡化了代碼量。我們需要增加新功能時也方便悉罕,這樣也提高了系統(tǒng)擴(kuò)展性赤屋。日志功能、事務(wù)管理等等場景都用到了 AOP 壁袄。

那你聊聊Spring AOP 和 AspectJ AOP 有什么區(qū)別类早? 平時在項(xiàng)目中你一般用的哪個

Spring AOP 屬于運(yùn)行時增強(qiáng),而 AspectJ 是編譯時增強(qiáng)嗜逻。 Spring AOP 基于代理(Proxying)涩僻,而 AspectJ 基于字節(jié)碼操作(Bytecode Manipulation)。

Spring AOP 已經(jīng)集成了 AspectJ 栈顷,AspectJ 應(yīng)該算的上是 Java 生態(tài)系統(tǒng)中最完整的 AOP 框架了逆日。AspectJ 相比于 Spring AOP 功能更加強(qiáng)大,但是 Spring AOP 相對來說更簡單萄凤,

我們一般在項(xiàng)目中用的AspectJ AoP比較多點(diǎn)

Spring 的 bean 作用域(scope)類型室抽,Spring Bean是否是線程安全的

Spring容器中的Bean是否線程安全,容器本身并沒有提供Bean的線程安全策略蛙卤,因此可以說Spring容器中的Bean本身不具備線程安全的特性狠半,但是具體還是要結(jié)合具體scope的Bean去研究噩死。

Spring 的 bean 作用域(scope)類型

  • singleton:單例,默認(rèn)作用域神年。
  • prototype:原型已维,每次創(chuàng)建一個新對象。
  • request:請求已日,每次Http請求創(chuàng)建一個新對象垛耳,適用于WebApplicationContext環(huán)境下。
  • session:會話飘千,同一個會話共享一個實(shí)例堂鲜,不同會話使用不用的實(shí)例。

線程安全這個問題护奈,要從單例與原型Bean分別進(jìn)行說明缔莲。

  • 對于原型Bean,每次創(chuàng)建一個新對象,也就是線程之間并不存在Bean共享霉旗,自然是不會有線程安全的問題痴奏。
  • 對于單例Bean,所有線程都共享一個單例實(shí)例Bean,因此是存在資源的競爭。
  • 如果單例Bean,是一個無狀態(tài)Bean厌秒,也就是線程中的操作不會對Bean的成員執(zhí)行查詢以外的操作读拆,那么這個單例Bean是線程安全的。比如Spring mvc 的 Controller鸵闪、Service檐晕、Dao等,這些Bean大多是無狀態(tài)的蚌讼,只關(guān)注于方法本身辟灰。
    總結(jié)下
  • 在@Controller/@Service等容器中,默認(rèn)情況下篡石,scope值是單例-singleton的伞矩,也是線程不安全的。
  • 盡量不要在@Controller/@Service等容器中定義靜態(tài)變量夏志,不論是單例(singleton)還是多實(shí)例(prototype)他都是線程不安全的乃坤。
  • 默認(rèn)注入的Bean對象,在不設(shè)置scope的時候他也是線程不安全的沟蔑。
  • 一定要定義變量的話湿诊,用ThreadLocal來封裝,這個是線程安全的

那你說說@Component 和 @Bean 的區(qū)別是什么瘦材?

  • 作用對象不同: @Component 注解作用于類厅须,而@Bean注解作用于方法。
  • @Component通常是通過類路徑掃描來自動偵測以及自動裝配到Spring容器中(我們可以使用 @ComponentScan 注解定義要掃描的路徑從中找出標(biāo)識了需要裝配的類自動裝配到 Spring 的 bean 容器中)食棕。@Bean 注解通常是我們在標(biāo)有該注解的方法中定義產(chǎn)生這個 bean,@Bean告訴了Spring這是某個類的示例朗和,當(dāng)我需要用它的時候還給我错沽。
  • @Bean 注解比 Component 注解的自定義性更強(qiáng),而且很多地方我們只能通過 @Bean 注解來注冊bean眶拉。比如當(dāng)我們引用第三方庫中的類需要裝配到 Spring容器時千埃,則只能通過 @Bean來實(shí)現(xiàn)。

那你聊聊什么是 spring 裝配忆植,自動裝配有哪些方式放可?

當(dāng) bean 在 Spring 容器中組合在一起時,它被稱為裝配或 bean 裝配朝刊。 Spring 容器需要知道需要什么 bean 以及容器應(yīng)該如何使用依賴注入來將 bean 綁定在一起耀里,同時裝配 bean。

Spring 容器能夠自動裝配 bean拾氓。也就是說冯挎,可以通過檢查 BeanFactory 的內(nèi)容讓 Spring 自動解析 bean 的協(xié)作者。

自動裝配的不同模式:

  • no - 這是默認(rèn)設(shè)置咙鞍,表示沒有自動裝配织堂。應(yīng)使用顯式 bean 引用進(jìn)行裝配。
  • byName - 它根據(jù) bean 的名稱注入對象依賴項(xiàng)奶陈。它匹配并裝配其屬性與 XML 文件中由相同名稱定義的 bean。
  • byType - 它根據(jù)類型注入對象依賴項(xiàng)附较。如果屬性的類型與 XML 文件中的一個 bean 名稱匹配吃粒,則匹配并裝配屬性。
  • 構(gòu)造函數(shù) - 它通過調(diào)用類的構(gòu)造函數(shù)來注入依賴項(xiàng)拒课。它有大量的參數(shù)徐勃。
  • autodetect - 首先容器嘗試通過構(gòu)造函數(shù)使用 autowire 裝配,如果不能早像,則嘗試通過 byType 自動裝配僻肖。

你知道@Autowired 注解有什么用? 那@Qualifier呢卢鹦?

  • @Autowired 可以更準(zhǔn)確地控制應(yīng)該在何處以及如何進(jìn)行自動裝配臀脏。此注解用于在 setter 方法,構(gòu)造函數(shù)冀自,具有任意名稱或多個參數(shù)的屬性或方法上自動裝配 bean揉稚。默認(rèn)情況下,它是類型驅(qū)動的注入熬粗。
  • 當(dāng)您創(chuàng)建多個相同類型的 bean 并希望僅使用屬性裝配其中一個 bean 時搀玖,您可以使用@Qualifier 注解和 @Autowired 通過指定應(yīng)該裝配哪個確切的 bean 來消除歧義。

說說Spring Bean的生命周期

準(zhǔn)確的了解Spring Bean的生命周期是非常必要的驻呐。我們通常使用ApplicationContext作為Spring容器灌诅。這里芳来,我們講的也是 ApplicationContext中Bean的生命周期。而實(shí)際上BeanFactory也是差不多的猜拾,只不過處理器需要手動注冊即舌。


image

image

其實(shí)在整個Bean的生命周期,也就是Bean初始化完成之前关带,我們的spring給我們提供了太多的拓展點(diǎn)了侥涵,可以讓我們靈活的去解決我們不同的需求,下面來總結(jié)總結(jié)這些鉤子函數(shù)
Bean的完整生命周期經(jīng)歷了各種方法調(diào)用宋雏,這些方法可以劃分為以下幾類:

  • Bean自身的方法 ∥咂:  這個包括了Bean本身調(diào)用的方法和通過配置文件中<bean>的init-method和destroy-method指定的方法
  • Bean級生命周期接口方法  :  這個包括了BeanNameAware磨总、BeanFactoryAware嗦明、InitializingBean和DiposableBean這些接口的方法
  • 容器級生命周期接口方法  :  這個包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 這兩個接口實(shí)現(xiàn)蚪燕,一般稱它們的實(shí)現(xiàn)類為“后處理器”娶牌。
image

聊聊Web容器的啟動過程吧,說說它的啟動方式

首先我們來聊聊Spring容器的啟動方式馆纳,也就是我們整個web項(xiàng)目的一個啟動方式诗良,目前主流的公司一般分為2種,一種基于ssm的啟動流程鲁驶,一種是基于SpringBoot的啟動過程鉴裹,今天我就來說說ssm的一個啟動流程,springboot的下次和springcloud系列一起講

SSM的SpringBoot的啟動流程


image
  • 首先钥弯,對于一個web應(yīng)用径荔,其部署在web容器中,web容器提供其一個全局的上下文環(huán)境脆霎,這個上下文就是ServletContext总处,其為后面的spring IoC容器提供宿主環(huán)境;

  • 然后就是我們的web.xml睛蛛,在幾年前的項(xiàng)目我想大家都有碰到過吧鹦马,在web.xml中會提供有contextLoaderListener。在web容器啟動時忆肾,會觸發(fā)容器初始化事件菠红,此時 contextLoaderListener會監(jiān)聽到這個事件,其contextInitialized方法會被調(diào)用难菌,在這個方法中试溯,spring會初始 化一個啟動上下文,這個上下文被稱為根上下文郊酒,即WebApplicationContext遇绞,這是一個接口類键袱,確切的說,其實(shí)際的實(shí)現(xiàn)類是 XmlWebApplicationContext摹闽。這個就是spring的IoC容器蹄咖,其對應(yīng)的Bean定義的配置由web.xml中的 context-param標(biāo)簽指定。在這個IoC容器初始化完畢后付鹿,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE為屬性Key澜汤,將其存儲到ServletContext中,便于獲榷尕摇俊抵;

  • 再 次,contextLoaderListener監(jiān)聽器初始化完畢后坐梯,開始初始化web.xml中配置的Servlet徽诲,這里是DispatcherServlet,這個servlet實(shí)際上是一個標(biāo)準(zhǔn)的前端控制器吵血,用以轉(zhuǎn)發(fā)谎替、匹配、處理每個servlet請 求蹋辅。DispatcherServlet上下文在初始化的時候會建立自己的IoC上下文钱贯,用以持有spring mvc相關(guān)的bean。在建立DispatcherServlet自己的IoC上下文時侦另,會利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先從ServletContext中獲取之前的根上下文(即WebApplicationContext)作為自己上下文的parent上下文秩命。有了這個 parent上下文之后,再初始化自己持有的上下文淋肾。這個DispatcherServlet初始化自己上下文的工作在其initStrategies方 法中可以看到,大概的工作就是初始化處理器映射爸邢、視圖解析等樊卓。這個servlet自己持有的上下文默認(rèn)實(shí)現(xiàn)類也是 XmlWebApplicationContext。初始化完畢后杠河,spring以與servlet的名字相關(guān)(此處不是簡單的以servlet名為 Key碌尔,而是通過一些轉(zhuǎn)換,具體可自行查看源碼)的屬性為屬性Key券敌,也將其存到ServletContext中唾戚,以便后續(xù)使用。這樣每個servlet 就持有自己的上下文待诅,即擁有自己獨(dú)立的bean空間叹坦,同時各個servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定義的那些 bean卑雁。

上面就是我們整個SSM的啟動過程了募书,也是幾年前大多數(shù)企業(yè)級開發(fā)的一個整個項(xiàng)目啟動流程哦绪囱,至于SpringBoot的方式,下一篇springboot再在

那你聊聊Spring容器的加載過程唄(ioc的啟動流程)

上面的過程是整個web容器的啟動過程莹捡,它里面包含了我們spring容器的啟動流程鬼吵,我現(xiàn)在就給大家詳細(xì)的講解我們ioc啟動的加載過程

AbstractApplicationContext.java 里的 refresh() 方法,這個方法就是構(gòu)建整個 IoC 容器過程的完整代碼篮赢,只要把這個方法里的每一行代碼都了解了齿椅,基本上了解了大部分 ioc 的原理和功能。


image
  • prepareRefresh() 方法:為刷新準(zhǔn)備新的上下文環(huán)境启泣,設(shè)置其啟動日期和活動標(biāo)志以及執(zhí)行一些屬性的初始化涣脚。主要是一些準(zhǔn)備工作,不是很重要的方法种远,可以先不關(guān)注
  • obtainFreshBeanFactory() 方法:該方法會解析所有 Spring 配置文件(通常我們會放在 resources 目錄下)涩澡,將所有 Spring 配置文件中的 bean 定義封裝成 BeanDefinition,加載到 BeanFactory 中坠敷。常見的妙同,如果解析到<context:component-scan base-package="com.joonwhee.open" /> 注解時,會掃描 base-package 指定的目錄膝迎,將該目錄下使用指定注解(@Controller粥帚、@Service、@Component限次、@Repository)的 bean 定義也同樣封裝成 BeanDefinition芒涡,加載到 BeanFactory 中。 上面提到的“加載到 BeanFactory 中”的內(nèi)容主要指的是以下3個緩存:
    • beanDefinitionNames緩存:所有被加載到 BeanFactory 中的 bean 的 beanName 集合卖漫。
    • beanDefinitionMap緩存:所有被加載到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射费尽。
    • aliasMap緩存:所有被加載到 BeanFactory 中的 bean 的 beanName 和別名映射。
  • prepareBeanFactory(beanFactory) 方法:配置 beanFactory 的標(biāo)準(zhǔn)上下文特征羊始,例如上下文的 ClassLoader旱幼、后置處理器等。這個方法會注冊3個默認(rèn)環(huán)境 bean:environment突委、systemProperties 和 systemEnvironment柏卤,注冊 2 個 bean 后置處理器:ApplicationContextAwareProcessor 和 ApplicationListenerDetector。
  • postProcessBeanFactory(beanFactory) 方法:允許子類對 BeanFactory 進(jìn)行后續(xù)處理匀油,默認(rèn)實(shí)現(xiàn)為空缘缚,留給子類實(shí)現(xiàn)。
  • invokeBeanFactoryPostProcessors(beanFactory) 方法:實(shí)例化和調(diào)用所有 BeanFactoryPostProcessor敌蚜,包括其子類 BeanDefinitionRegistryPostProcessor桥滨。
  • registerBeanPostProcessors(beanFactory) 方法:注冊所有的 BeanPostProcessor,將所有實(shí)現(xiàn)了 BeanPostProcessor 接口的類加載到 BeanFactory 中。
  • initMessageSource() 方法:初始化消息資源 MessageSource
  • initApplicationEventMulticaster() 方法:初始化應(yīng)用的事件廣播器 ApplicationEventMulticaster该园。
  • onRefresh() 方法:該方法為模板方法酸舍,提供給子類擴(kuò)展實(shí)現(xiàn),可以重寫以添加特定于上下文的刷新工作里初,默認(rèn)實(shí)現(xiàn)為空啃勉。(在springboot中這個方法可是加載tomcat容器的)
  • registerListeners() 方法:注冊監(jiān)聽器。
  • finishBeanFactoryInitialization(beanFactory) 方法:該方法會實(shí)例化所有剩余的非懶加載單例 bean双妨。除了一些內(nèi)部的 bean淮阐、實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口的 bean、實(shí)現(xiàn)了 BeanPostProcessor 接口的 bean刁品,其他的非懶加載單例 bean 都會在這個方法中被實(shí)例化泣特,并且 BeanPostProcessor 的觸發(fā)也是在這個方法中。(這個方法其實(shí)是核心方法了挑随,包含我們的bea從beandifinition變成我們的容器中的bean最核心的方法了)
  • finishRefresh() 方法:完成此上下文的刷新足画,主要是推送上下文刷新完畢事件(ContextRefreshedEvent )到監(jiān)聽器笛园。

比較重要的是下面幾個點(diǎn)

  • obtainFreshBeanFactory 創(chuàng)建一個新的 BeanFactory库继、讀取和解析 bean 定義葬燎。
  • invokeBeanFactoryPostProcessors 提供給開發(fā)者對 BeanFactory 進(jìn)行擴(kuò)展。
  • registerBeanPostProcessors 提供給開發(fā)者對 bean 進(jìn)行擴(kuò)展拌汇。
  • finishBeanFactoryInitialization 實(shí)例化剩余的所有非懶加載單例 bean柒桑。

SpringMVC 工作原理了解嗎? 基于頁面Controller的類型

  • 客戶端(瀏覽器)發(fā)送請求,直接請求到 DispatcherServlet噪舀。
  • DispatcherServlet 根據(jù)請求信息調(diào)用 HandlerMapping魁淳,解析請求對應(yīng)的 Handler。
  • 解析到對應(yīng)的 Handler(也就是我們平常說的 Controller 控制器)后与倡,開始由 HandlerAdapter 適配器處理界逛。
  • HandlerAdapter 會根據(jù) Handler 來調(diào)用真正的處理器來處理請求,并處理相應(yīng)的業(yè)務(wù)邏輯纺座。
  • 處理器處理完業(yè)務(wù)后息拜,會返回一個 ModelAndView 對象,Model 是返回的數(shù)據(jù)對象比驻,View 是個邏輯上的 View该溯。
  • ViewResolver 會根據(jù)邏輯 View 查找實(shí)際的 View岛抄。
  • DispaterServlet 把返回的 Model 傳給 View(視圖渲染)别惦。
  • 把 View 返回給請求者(瀏覽器)

聊聊Spring 框架中用到了哪些設(shè)計模式?

  • 工廠設(shè)計模式 : Spring使用工廠模式通過 BeanFactory夫椭、ApplicationContext 創(chuàng)建 bean 對象掸掸。
  • 代理設(shè)計模式 : Spring AOP 功能的實(shí)現(xiàn)。
  • 單例設(shè)計模式 : Spring 中的 Bean 默認(rèn)都是單例的。
  • 模板方法模式 : Spring 中 jdbcTemplate扰付、hibernateTemplate 等以 Template 結(jié)尾的對數(shù)據(jù)庫操作的類堤撵,它們就使用到了模板模式。
  • 觀察者模式: Spring 事件驅(qū)動模型就是觀察者模式很經(jīng)典的一個應(yīng)用羽莺。
  • 適配器模式 :Spring AOP 的增強(qiáng)或通知(Advice)使用到了適配器模式实昨、spring MVC 中也是用到了適配器模式適配Controller。

spring事務(wù)熟悉不盐固,一般你用哪種實(shí)現(xiàn)方式

  • 編程式事務(wù)荒给,在代碼中硬編碼。(不推薦使用)
  • 聲明式事務(wù)刁卜,在配置文件中配置(推薦使用)
    一般在我們企業(yè)級開發(fā)的過程中志电,一般都是用的聲明式事務(wù),聲明式事務(wù)也分為2種一種是基于xml的蛔趴,一種基于注解的挑辆,一般用注解的多點(diǎn)

說說 Spring 事務(wù)中哪幾種事務(wù)傳播行為?

支持當(dāng)前事務(wù)的情況:

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果當(dāng)前存在事務(wù),則加入該事務(wù)孝情;如果當(dāng)前沒有事務(wù)鱼蝉,則創(chuàng)建一個新的事務(wù)。

  • TransactionDefinition.PROPAGATION_SUPPORTS: 如果當(dāng)前存在事務(wù)咧叭,則加入該事務(wù)蚀乔;如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行菲茬。

  • TransactionDefinition.PROPAGATION_MANDATORY: 如果當(dāng)前存在事務(wù)吉挣,則加入該事務(wù);如果當(dāng)前沒有事務(wù)婉弹,則拋出異常睬魂。(mandatory:強(qiáng)制性)
    不支持當(dāng)前事務(wù)的情況:

  • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 創(chuàng)建一個新的事務(wù),如果當(dāng)前存在事務(wù)镀赌,則把當(dāng)前事務(wù)掛起氯哮。

  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù)商佛,則把當(dāng)前事務(wù)掛起喉钢。

  • TransactionDefinition.PROPAGATION_NEVER: 以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù)良姆,則拋出異常肠虽。

說說BeanFactory 和 FactoryBean的區(qū)別?

  • BeanFactory是個Factory玛追,也就是IOC容器或?qū)ο蠊S税课,在Spring中闲延,所有的Bean都是由BeanFactory(也就是IOC容器)來進(jìn)行管理的,提供了實(shí)例化對象和拿對象的功能韩玩。
  • FactoryBean是個Bean垒玲,這個Bean不是簡單的Bean,而是一個能生產(chǎn)或者修飾對象生成的工廠Bean,它的實(shí)現(xiàn)與設(shè)計模式中的工廠模式和修飾器模式類似找颓。

聊聊Spring的循環(huán)依賴吧

  • spring的循環(huán)依賴主要是指兩個類相互之間通過@Autowired自動依賴注入對方合愈,即類A包含一個類B的對象引用并需要自動注入,類B包含一個類A的對象引用也需要自動注入击狮。
  • 對于循環(huán)依賴問題想暗,spring根據(jù)注入方式的不同,采取不同的處理策略帘不,對于雙方都是使用屬性值注入或者setter方法注入说莫,則spring可以自動解決循環(huán)依賴注入問題,應(yīng)用程序可以成功啟動寞焙;對于雙方都是使用構(gòu)造函數(shù)注入對方或者主bean對象(Spring在啟動過程中储狭,先加載的bean對象)使用構(gòu)造函數(shù)注入,則spring無法解決循環(huán)依賴注入捣郊,程序報錯無法啟動辽狈。

首先spring在單例的情況下是默認(rèn)支持循環(huán)引用的;在不做任何配置的情況下呛牲,兩個bean相互依賴是能初始化成功的刮萌;spring源碼中在創(chuàng)建bean的時候先創(chuàng)建這個bean的對象,創(chuàng)建對象完成之后通過判斷容器對象的allowCircularReferences屬性決定是否允許緩存這個臨時對象娘扩,如果能被緩存成功則通過緩存提前暴露這個臨時對象來完成循環(huán)依賴着茸;而這個屬性默認(rèn)為true,所以說spring默認(rèn)支持循環(huán)依賴的琐旁,但是這個屬性spring提供了api讓程序員來修改涮阔,所以spring也提供了關(guān)閉循環(huán)引用的功能;

那你說說Spring是如何解決循環(huán)引用的

首先灰殴,Spring內(nèi)部維護(hù)了三個Map敬特,也就是我們通常說的三級緩存。

筆者翻閱Spring文檔倒是沒有找到三級緩存的概念牺陶,可能也是本土為了方便理解的詞匯伟阔。

在Spring的DefaultSingletonBeanRegistry類中,你會赫然發(fā)現(xiàn)類上方掛著這三個Map:

  • singletonObjects 它是我們最熟悉的朋友掰伸,俗稱“單例池”“容器”皱炉,緩存創(chuàng)建完成單例Bean的地方。
  • singletonFactories 映射創(chuàng)建Bean的原始工廠
  • earlySingletonObjects 映射Bean的早期引用碱工,也就是說在這個Map里的Bean不是完整的娃承,甚至還不能稱之為“Bean”,只是一個Instance.
    后兩個Map其實(shí)是“墊腳石”級別的怕篷,只是創(chuàng)建Bean的時候历筝,用來借助了一下,創(chuàng)建完成就清掉了廊谓。

所以筆者前文對“三級緩存”這個詞有些迷惑梳猪,可能是因?yàn)樽⑨尪际且訡ache of開頭吧。

為什么成為后兩個Map為墊腳石蒸痹,假設(shè)最終放在singletonObjects的Bean是你想要的一杯“涼白開”春弥。

那么Spring準(zhǔn)備了兩個杯子,即singletonFactories和earlySingletonObjects來回“倒騰”幾番叠荠,把熱水晾成“涼白開”放到singletonObjects中匿沛。

循環(huán)引用的不同的場景,有哪些方法可以解決循環(huán)引用

image

為啥有些注入方式不能解決循環(huán)依賴問題呢榛鼎?源碼中看出逃呼,他們并沒有用到那個earlySingletonObjects這個緩存,所以就不能解決循環(huán)依賴

解決Spring無法解決的循環(huán)依賴的一些方式

項(xiàng)目中如果出現(xiàn)循環(huán)依賴問題者娱,說明是spring默認(rèn)無法解決的循環(huán)依賴抡笼,要看項(xiàng)目的打印日志,屬于哪種循環(huán)依賴黄鳍。目前包含下面幾種情況:


image

生成代理對象產(chǎn)生的循環(huán)依賴
這類循環(huán)依賴問題解決方法很多推姻,主要有:

  • 使用@Lazy注解,延遲加載
  • 使用@DependsOn注解框沟,指定加載先后關(guān)系
  • 修改文件名稱藏古,改變循環(huán)依賴類的加載順序

說說什么是Mybatis?

  • Mybatis是一個半ORM(對象關(guān)系映射)框架忍燥,它內(nèi)部封裝了JDBC校翔,加載驅(qū)動、創(chuàng)建連接灾前、創(chuàng)建statement等繁雜的過程防症,開發(fā)者開發(fā)時只需要關(guān)注如何編寫SQL語句,可以嚴(yán)格控制sql執(zhí)行性能哎甲,靈活度高蔫敲。
  • 作為一個半ORM框架,MyBatis 可以使用 XML 或注解來配置和映射原生信息炭玫,將 POJO映射成數(shù)據(jù)庫中的記錄奈嘿,避免了幾乎所有的 JDBC 代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集。

說說 #{}和${}的區(qū)別是什么吞加?

  • {}是預(yù)編譯處理裙犹,${}是字符串替換尽狠。

  • Mybatis在處理#{}時,會將sql中的#{}替換為?號叶圃,調(diào)用PreparedStatement的set方法來賦值袄膏;
  • Mybatis在處理{}時,就是把{}替換成變量的值掺冠。
  • 使用#{}可以有效的防止SQL注入沉馆,提高系統(tǒng)安全性。

說說Mybatis的一級德崭、二級緩存:

一級緩存 事務(wù)范圍:緩存只能被當(dāng)前事務(wù)訪問斥黑。緩存的生命周期 依賴于事務(wù)的生命周期當(dāng)事務(wù)結(jié)束時,緩存也就結(jié)束生命周期眉厨。 在此范圍下锌奴,緩存的介質(zhì)是內(nèi)存。 二級緩存 進(jìn)程范圍:緩存被進(jìn)程內(nèi)的所有事務(wù)共享憾股。這些事務(wù)有 可能是并發(fā)訪問緩存缨叫,因此必須對緩存采取必要的事務(wù)隔離機(jī)制。 緩存的生命周期依賴于進(jìn)程的生命周期荔燎,進(jìn)程結(jié)束時耻姥, 緩存也就結(jié)束了生命周期。進(jìn)程范圍的緩存可能會存放大量的數(shù)據(jù)有咨, 所以存放的介質(zhì)可以是內(nèi)存或硬盤琐簇。

聊聊Mybatis的一個整體的架構(gòu)吧

image

其實(shí)哈,我覺得mybatis框架主要需要做的事情我們是知道的座享,為啥呢婉商?因?yàn)槠鋵?shí)如果我們沒有mybatis 我們也可以做數(shù)據(jù)庫操作對吧,那就是jdbc 的操作唄渣叛,那其實(shí)mybatis就是在封裝在jdbc之上的一個框架而已丈秩,它所需要做的就是那么多,我來總結(jié)下

  • 首先就是一些基礎(chǔ)組件 連接管理淳衙,事務(wù)管理蘑秽,配置的加載,緩存的處理
  • 然后是核心的功能箫攀,我們參數(shù)映射肠牲,我們的sql解析,sql執(zhí)行靴跛,我們的結(jié)果映射
  • 之上就是封裝我們統(tǒng)一的crud接口就好了缀雳,對就這么多咯。

上面就是整個mybatis做的事情了梢睛,當(dāng)然每一塊功能處理起來也是不那么簡單的肥印。

對Mybatis的源碼熟悉嗎识椰,找你熟悉的地方聊聊唄

image

上面的圖是整個mybatis的一個核心流程,其實(shí)不過是spring也好深碱,mybatis也好腹鹉,所有的框架我們都可以把他們分為2個部分,一個就是初始化的過程莹痢,就是相當(dāng)于做好準(zhǔn)備工作來接客的過程,第二個就是實(shí)際的接客過程了墓赴,所以不管是講哪個框架的源碼都是這樣來的竞膳,mybatis當(dāng)然也是不例外的

  • 初始化過程
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("configuration.xml"));

就是我們mybatis的核心在SqlSessionFactory,首先SqlSessionFactory build出來 這個過程就會涉及到解析各種配置文件诫硕,第一個要解析的就是configuration然后他的里面有很多的標(biāo)簽坦辟,你比如說properties等節(jié)點(diǎn),然后里面有一個mapper節(jié)點(diǎn)章办,就是可以找到我們的mapper.xml 然后又去解析里面的節(jié)點(diǎn)锉走,報告各種cach,select 等等,之后把解析好之后xml通過命名空間和我們的mapper接口綁定藕届,并生成代碼對象挪蹭,把他放到konwsmapper 這個map容器里面。最后就可以生成這個SqlSessionFactory

  • 真正的執(zhí)行過程
    就是當(dāng)我們的mybatis準(zhǔn)備好之后呢休偶?我們拿到這個sqlsession對象之后梁厉,如果是不要spring集成的話,那么接下來當(dāng)然是要去獲取我們的mapper對象了 sqlsession.getMapper踏兜,當(dāng)然這個獲取的也是代理對象拉词顾,然后到MapperMethod,然后SqlSession 將查詢方法轉(zhuǎn)發(fā)給 Executor碱妆。Executor 基于 JDBC 訪問數(shù)據(jù)庫獲取數(shù)據(jù)肉盹。Executor 通過反射將數(shù)據(jù)轉(zhuǎn)換成 POJO并返回給 SqlSession。將數(shù)據(jù)返回給調(diào)用者疹尾。

結(jié)束

接下來我們看看SpringBoot 和SpringCloud的組件哈上忍,東西還很多,大家一起加油

日常求贊

好了各位纳本,以上就是這篇文章的全部內(nèi)容了睡雇,能看到這里的人呀,都是真粉饮醇。

創(chuàng)作不易它抱,各位的支持和認(rèn)可,就是我創(chuàng)作的最大動力朴艰,我們下篇文章見

微信 搜 "六脈神劍的程序人生" 回復(fù)888 有我找的許多的資料送給大家

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末观蓄,一起剝皮案震驚了整個濱河市混移,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌侮穿,老刑警劉巖歌径,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異亲茅,居然都是意外死亡回铛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門克锣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茵肃,“玉大人,你說我怎么就攤上這事袭祟⊙椴校” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵巾乳,是天一觀的道長您没。 經(jīng)常有香客問我,道長胆绊,這世上最難降的妖魔是什么氨鹏? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮压状,結(jié)果婚禮上喻犁,老公的妹妹穿的比我還像新娘。我一直安慰自己何缓,他們只是感情好肢础,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著碌廓,像睡著了一般传轰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谷婆,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天慨蛙,我揣著相機(jī)與錄音,去河邊找鬼纪挎。 笑死期贫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的异袄。 我是一名探鬼主播通砍,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了封孙?” 一聲冷哼從身側(cè)響起迹冤,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎虎忌,沒想到半個月后泡徙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡膜蠢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年堪藐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挑围。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡礁竞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贪惹,到底是詐尸還是另有隱情苏章,我是刑警寧澤寂嘉,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布奏瞬,位于F島的核電站,受9級特大地震影響泉孩,放射性物質(zhì)發(fā)生泄漏硼端。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一寓搬、第九天 我趴在偏房一處隱蔽的房頂上張望珍昨。 院中可真熱鬧,春花似錦句喷、人聲如沸镣典。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兄春。三九已至,卻和暖如春锡溯,著一層夾襖步出監(jiān)牢的瞬間赶舆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工祭饭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留芜茵,地道東北人。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓倡蝙,卻偏偏與公主長得像九串,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子寺鸥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容