點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
1、Spring是什么?
Spring是一個(gè)輕量級(jí)的IoC和AOP容器框架。是為Java應(yīng)用程序提供基礎(chǔ)性服務(wù)的一套框架,目的是用于簡(jiǎn)化企業(yè)應(yīng)用程序的開(kāi)發(fā),它使得開(kāi)發(fā)者只需要關(guān)心業(yè)務(wù)需求。主要包括以下七個(gè)模塊:
Spring Context:提供框架式的Bean訪問(wèn)方式,以及企業(yè)級(jí)功能(JNDI、定時(shí)任務(wù)等);
Spring Core:核心類庫(kù),所有功能都依賴于該類庫(kù),提供IOC和DI服務(wù);
Spring AOP:AOP服務(wù);
Spring Web:提供了基本的面向Web的綜合特性,提供對(duì)常見(jiàn)框架如Struts2的支持,Spring能夠管理這些框架,將Spring的資源注入給框架,也能在這些框架的前后插入攔截器;
Spring MVC:提供面向Web應(yīng)用的Model-View-Controller,即MVC實(shí)現(xiàn)。
Spring DAO:對(duì)JDBC的抽象封裝,簡(jiǎn)化了數(shù)據(jù)訪問(wèn)異常的處理,并能統(tǒng)一管理JDBC事務(wù);
Spring ORM:對(duì)現(xiàn)有的ORM框架的支持;
下圖對(duì)應(yīng)的是Spring 4.x的版本,5.x版本中Web模塊的Portlet組件已經(jīng)被廢棄
2、Spring 的優(yōu)點(diǎn)?
(1)spring屬于低侵入式設(shè)計(jì),代碼的污染極低;
(2)spring的DI機(jī)制將對(duì)象之間的依賴關(guān)系交由框架處理,減低組件的耦合性;
(3)Spring提供了AOP技術(shù),支持將一些通用任務(wù),如安全、事務(wù)、日志、權(quán)限等進(jìn)行集中式管理,從而提供更好的復(fù)用。
(4)spring對(duì)于主流的應(yīng)用框架提供了集成支持。
3、Spring的IoC理解:
(1)IOC就是控制反轉(zhuǎn),指創(chuàng)建對(duì)象的控制權(quán)轉(zhuǎn)移給Spring框架進(jìn)行管理,并由Spring根據(jù)配置文件去創(chuàng)建實(shí)例和管理各個(gè)實(shí)例之間的依賴關(guān)系,對(duì)象與對(duì)象之間松散耦合,也利于功能的復(fù)用。DI依賴注入,和控制反轉(zhuǎn)是同一個(gè)概念的不同角度的描述,即 應(yīng)用程序在運(yùn)行時(shí)依賴IoC容器來(lái)動(dòng)態(tài)注入對(duì)象需要的外部依賴。
(2)最直觀的表達(dá)就是,以前創(chuàng)建對(duì)象的主動(dòng)權(quán)和時(shí)機(jī)都是由自己把控的,IOC讓對(duì)象的創(chuàng)建不用去new了,可以由spring自動(dòng)生產(chǎn),使用java的反射機(jī)制,根據(jù)配置文件在運(yùn)行時(shí)動(dòng)態(tài)的去創(chuàng)建對(duì)象以及管理對(duì)象,并調(diào)用對(duì)象的方法的。
(3)Spring的IOC有三種注入方式 :構(gòu)造器注入、setter方法注入、根據(jù)注解注入。
4、Spring的AOP理解:
OOP面向?qū)ο螅试S開(kāi)發(fā)者定義縱向的關(guān)系,但并不適用于定義橫向的關(guān)系,會(huì)導(dǎo)致大量代碼的重復(fù),而不利于各個(gè)模塊的重用。
AOP,一般稱為面向切面,作為面向?qū)ο蟮囊环N補(bǔ)充,用于將那些與業(yè)務(wù)無(wú)關(guān),但卻對(duì)多個(gè)對(duì)象產(chǎn)生影響的公共行為和邏輯,抽取并封裝為一個(gè)可重用的模塊,這個(gè)模塊被命名為“切面”(Aspect),減少系統(tǒng)中的重復(fù)代碼,降低了模塊間的耦合度,提高系統(tǒng)的可維護(hù)性。可用于權(quán)限認(rèn)證、日志、事務(wù)處理。
AOP實(shí)現(xiàn)的關(guān)鍵在于 代理模式,AOP代理主要分為靜態(tài)代理和動(dòng)態(tài)代理。靜態(tài)代理的代表為AspectJ;動(dòng)態(tài)代理則以Spring AOP為代表。
(1)AspectJ是靜態(tài)代理,也稱為編譯時(shí)增強(qiáng),AOP框架會(huì)在編譯階段生成AOP代理類,并將AspectJ(切面)織入到Java字節(jié)碼中,運(yùn)行的時(shí)候就是增強(qiáng)之后的AOP對(duì)象。
(2)Spring AOP使用的動(dòng)態(tài)代理,所謂的動(dòng)態(tài)代理就是說(shuō)AOP框架不會(huì)去修改字節(jié)碼,而是每次運(yùn)行時(shí)在內(nèi)存中臨時(shí)為方法生成一個(gè)AOP對(duì)象,這個(gè)AOP對(duì)象包含了目標(biāo)對(duì)象的全部方法,并且在特定的切點(diǎn)做了增強(qiáng)處理,并回調(diào)原對(duì)象的方法。
Spring AOP中的動(dòng)態(tài)代理主要有兩種方式,JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理:
① JDK動(dòng)態(tài)代理只提供接口的代理,不支持類的代理,要求被代理類實(shí)現(xiàn)接口。JDK動(dòng)態(tài)代理的核心是InvocationHandler接口和Proxy類,在獲取代理對(duì)象時(shí),使用Proxy類來(lái)動(dòng)態(tài)創(chuàng)建目標(biāo)類的代理類(即最終真正的代理類,這個(gè)類繼承自Proxy并實(shí)現(xiàn)了我們定義的接口),當(dāng)代理對(duì)象調(diào)用真實(shí)對(duì)象的方法時(shí), InvocationHandler 通過(guò)invoke()方法反射來(lái)調(diào)用目標(biāo)類中的代碼,動(dòng)態(tài)地將橫切邏輯和業(yè)務(wù)編織在一起;
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最終生成的代理對(duì)象; method 是被代理目標(biāo)實(shí)例的某個(gè)具體方法; args 是被代理目標(biāo)實(shí)例某個(gè)方法的具體入?yún)? 在方法反射調(diào)用時(shí)使用。
② 如果被代理類沒(méi)有實(shí)現(xiàn)接口,那么Spring AOP會(huì)選擇使用CGLIB來(lái)動(dòng)態(tài)代理目標(biāo)類。CGLIB(Code Generation Library),是一個(gè)代碼生成的類庫(kù),可以在運(yùn)行時(shí)動(dòng)態(tài)的生成指定類的一個(gè)子類對(duì)象,并覆蓋其中特定方法并添加增強(qiáng)代碼,從而實(shí)現(xiàn)AOP。CGLIB是通過(guò)繼承的方式做的動(dòng)態(tài)代理,因此如果某個(gè)類被標(biāo)記為final,那么它是無(wú)法使用CGLIB做動(dòng)態(tài)代理的。
(3)靜態(tài)代理與動(dòng)態(tài)代理區(qū)別在于生成AOP代理對(duì)象的時(shí)機(jī)不同,相對(duì)來(lái)說(shuō)AspectJ的靜態(tài)代理方式具有更好的性能,但是AspectJ需要特定的編譯器進(jìn)行處理,而Spring AOP則無(wú)需特定的編譯器處理。
IoC讓相互協(xié)作的組件保持松散的耦合,而AOP編程允許你把遍布于應(yīng)用各層的功能分離出來(lái)形成可重用的功能組件。
5、Spring AOP里面的幾個(gè)名詞的概念:
(1)連接點(diǎn)(Join point):指程序運(yùn)行過(guò)程中所執(zhí)行的方法。在Spring AOP中,一個(gè)連接點(diǎn)總代表一個(gè)方法的執(zhí)行。
(2)切面(Aspect):被抽取出來(lái)的公共模塊,可以用來(lái)會(huì)橫切多個(gè)對(duì)象。Aspect切面可以看成 Pointcut切點(diǎn) 和 Advice通知 的結(jié)合,一個(gè)切面可以由多個(gè)切點(diǎn)和通知組成。
在Spring AOP中,切面可以在類上使用 @AspectJ 注解來(lái)實(shí)現(xiàn)。
(3)切點(diǎn)(Pointcut):切點(diǎn)用于定義 要對(duì)哪些Join point進(jìn)行攔截。
切點(diǎn)分為execution方式和annotation方式。execution方式可以用路徑表達(dá)式指定對(duì)哪些方法攔截,比如指定攔截add*、search*。annotation方式可以指定被哪些注解修飾的代碼進(jìn)行攔截。
(4)通知(Advice):指要在連接點(diǎn)(Join Point)上執(zhí)行的動(dòng)作,即增強(qiáng)的邏輯,比如權(quán)限校驗(yàn)和、日志記錄等。通知有各種類型,包括Around、Before、After、After returning、After throwing。
(5)目標(biāo)對(duì)象(Target):包含連接點(diǎn)的對(duì)象,也稱作被通知(Advice)的對(duì)象。 由于Spring AOP是通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)的,所以這個(gè)對(duì)象永遠(yuǎn)是一個(gè)代理對(duì)象。
(6)織入(Weaving):通過(guò)動(dòng)態(tài)代理,在目標(biāo)對(duì)象(Target)的方法(即連接點(diǎn)Join point)中執(zhí)行增強(qiáng)邏輯(Advice)的過(guò)程。
(7)引入(Introduction):添加額外的方法或者字段到被通知的類。Spring允許引入新的接口(以及對(duì)應(yīng)的實(shí)現(xiàn))到任何被代理的對(duì)象。例如,你可以使用一個(gè)引入來(lái)使bean實(shí)現(xiàn) IsModified 接口,以便簡(jiǎn)化緩存機(jī)制。
幾個(gè)概念的關(guān)系圖可以參考下圖:

網(wǎng)上有張非常形象的圖,描述了各個(gè)概念所處的場(chǎng)景和作用,貼在這里供大家理解:
6、Spring通知(Advice)有哪些類型?
(1)前置通知(Before Advice):在連接點(diǎn)(Join point)之前執(zhí)行的通知。
(2)后置通知(After Advice):當(dāng)連接點(diǎn)退出的時(shí)候執(zhí)行的通知(不論是正常返回還是異常退出)。
(3)環(huán)繞通知(Around Advice):包圍一個(gè)連接點(diǎn)的通知,這是最強(qiáng)大的一種通知類型。 環(huán)繞通知可以在方法調(diào)用前后完成自定義的行為。它也可以選擇是否繼續(xù)執(zhí)行連接點(diǎn)或直接返回它們自己的返回值或拋出異常來(lái)結(jié)束執(zhí)行。
(4)返回后通知(AfterReturning Advice):在連接點(diǎn)正常完成后執(zhí)行的通知(如果連接點(diǎn)拋出異常,則不執(zhí)行)
(5)拋出異常后通知(AfterThrowing advice):在方法拋出異常退出時(shí)執(zhí)行的通知

同一個(gè)Aspect,不同advice的執(zhí)行順序:
(1)沒(méi)有異常情況下的執(zhí)行順序:
around before advice
before advice
target method 執(zhí)行
around after advice
after advice
afterReturning
(2)有異常情況下的執(zhí)行順序:
7、Spring容器的啟動(dòng)流程:
詳細(xì)內(nèi)容可以閱讀這篇文章:https://blog.csdn.net/a745233700/article/details/113761271
(1)初始化Spring容器,注冊(cè)內(nèi)置的BeanPostProcessor的BeanDefinition到容器中:
① 實(shí)例化BeanFactory【DefaultListableBeanFactory】工廠,用于生成Bean對(duì)象
② 實(shí)例化BeanDefinitionReader注解配置讀取器,用于對(duì)特定注解(如@Service、@Repository)的類進(jìn)行讀取轉(zhuǎn)化成 BeanDefinition 對(duì)象,(BeanDefinition 是 Spring 中極其重要的一個(gè)概念,它存儲(chǔ)了 bean 對(duì)象的所有特征信息,如是否單例,是否懶加載,factoryBeanName 等)
③ 實(shí)例化ClassPathBeanDefinitionScanner路徑掃描器,用于對(duì)指定的包目錄進(jìn)行掃描查找 bean 對(duì)象
(2)將配置類的BeanDefinition注冊(cè)到容器中:
(3)調(diào)用refresh()方法刷新容器:
① prepareRefresh()刷新前的預(yù)處理:
② obtainFreshBeanFactory():獲取在容器初始化時(shí)創(chuàng)建的BeanFactory:
③ prepareBeanFactory(beanFactory):BeanFactory的預(yù)處理工作,向容器中添加一些組件:
④ postProcessBeanFactory(beanFactory):子類重寫該方法,可以實(shí)現(xiàn)在BeanFactory創(chuàng)建并預(yù)處理完成以后做進(jìn)一步的設(shè)置
⑤ invokeBeanFactoryPostProcessors(beanFactory):在BeanFactory標(biāo)準(zhǔn)初始化之后執(zhí)行BeanFactoryPostProcessor的方法,即BeanFactory的后置處理器:
⑥ registerBeanPostProcessors(beanFactory):向容器中注冊(cè)Bean的后置處理器BeanPostProcessor,它的主要作用是干預(yù)Spring初始化bean的流程,從而完成代理、自動(dòng)注入、循環(huán)依賴等功能
⑦ initMessageSource():初始化MessageSource組件,主要用于做國(guó)際化功能,消息綁定與消息解析:
⑧ initApplicationEventMulticaster():初始化事件派發(fā)器,在注冊(cè)監(jiān)聽(tīng)器時(shí)會(huì)用到:
⑨ onRefresh():留給子容器、子類重寫這個(gè)方法,在容器刷新的時(shí)候可以自定義邏輯
⑩ registerListeners():注冊(cè)監(jiān)聽(tīng)器:將容器中所有的ApplicationListener注冊(cè)到事件派發(fā)器中,并派發(fā)之前步驟產(chǎn)生的事件:
? finishBeanFactoryInitialization(beanFactory):初始化所有剩下的單實(shí)例bean,核心方法是preInstantiateSingletons(),會(huì)調(diào)用getBean()方法創(chuàng)建對(duì)象;
? finishRefresh():發(fā)布BeanFactory容器刷新完成事件:
8、BeanFactory和ApplicationContext有什么區(qū)別?
BeanFactory和ApplicationContext是Spring的兩大核心接口,都可以當(dāng)做Spring的容器。
(1)BeanFactory是Spring里面最底層的接口,是IoC的核心,定義了IoC的基本功能,包含了各種Bean的定義、加載、實(shí)例化,依賴注入和生命周期管理。ApplicationContext接口作為BeanFactory的子類,除了提供BeanFactory所具有的功能外,還提供了更完整的框架功能:
繼承MessageSource,因此支持國(guó)際化。
資源文件訪問(wèn),如URL和文件(ResourceLoader)。
載入多個(gè)(有繼承關(guān)系)上下文(即同時(shí)加載多個(gè)配置文件) ,使得每一個(gè)上下文都專注于一個(gè)特定的層次,比如應(yīng)用的web層。
提供在監(jiān)聽(tīng)器中注冊(cè)bean的事件。
(2)①BeanFactroy采用的是延遲加載形式來(lái)注入Bean的,只有在使用到某個(gè)Bean時(shí)(調(diào)用getBean()),才對(duì)該Bean進(jìn)行加載實(shí)例化。這樣,我們就不能提前發(fā)現(xiàn)一些存在的Spring的配置問(wèn)題。如果Bean的某一個(gè)屬性沒(méi)有注入,BeanFacotry加載后,直至第一次使用調(diào)用getBean方法才會(huì)拋出異常。
②ApplicationContext,它是在容器啟動(dòng)時(shí),一次性創(chuàng)建了所有的Bean。這樣,在容器啟動(dòng)時(shí),我們就可以發(fā)現(xiàn)Spring中存在的配置錯(cuò)誤,這樣有利于檢查所依賴屬性是否注入。
③ApplicationContext啟動(dòng)后預(yù)載入所有的單實(shí)例Bean,所以在運(yùn)行的時(shí)候速度比較快,因?yàn)樗鼈円呀?jīng)創(chuàng)建好了。相對(duì)于BeanFactory,ApplicationContext 唯一的不足是占用內(nèi)存空間,當(dāng)應(yīng)用程序配置Bean較多時(shí),程序啟動(dòng)較慢。
(3)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但兩者之間的區(qū)別是:BeanFactory需要手動(dòng)注冊(cè),而ApplicationContext則是自動(dòng)注冊(cè)。
(4)BeanFactory通常以編程的方式被創(chuàng)建,ApplicationContext還能以聲明的方式創(chuàng)建,如使用ContextLoader。
9、Spring Bean的生命周期?
簡(jiǎn)單來(lái)說(shuō),Spring Bean的生命周期只有四個(gè)階段:實(shí)例化 Instantiation --> 屬性賦值 Populate --> 初始化 Initialization --> 銷毀 Destruction
但具體來(lái)說(shuō),Spring Bean的生命周期包含下圖的流程:

(1)實(shí)例化Bean:
對(duì)于BeanFactory容器,當(dāng)客戶向容器請(qǐng)求一個(gè)尚未初始化的bean時(shí),或初始化bean的時(shí)候需要注入另一個(gè)尚未初始化的依賴時(shí),容器就會(huì)調(diào)用createBean進(jìn)行實(shí)例化。
對(duì)于ApplicationContext容器,當(dāng)容器啟動(dòng)結(jié)束后,通過(guò)獲取BeanDefinition對(duì)象中的信息,實(shí)例化所有的bean。
(2)設(shè)置對(duì)象屬性(依賴注入):實(shí)例化后的對(duì)象被封裝在BeanWrapper對(duì)象中,緊接著,Spring根據(jù)BeanDefinition中的信息 以及 通過(guò)BeanWrapper提供的設(shè)置屬性的接口完成屬性設(shè)置與依賴注入。
(3)處理Aware接口:Spring會(huì)檢測(cè)該對(duì)象是否實(shí)現(xiàn)了xxxAware接口,通過(guò)Aware類型的接口,可以讓我們拿到Spring容器的一些資源:
①如果這個(gè)Bean實(shí)現(xiàn)了BeanNameAware接口,會(huì)調(diào)用它實(shí)現(xiàn)的setBeanName(String beanId)方法,傳入Bean的名字;
②如果這個(gè)Bean實(shí)現(xiàn)了BeanClassLoaderAware接口,調(diào)用setBeanClassLoader()方法,傳入ClassLoader對(duì)象的實(shí)例。
②如果這個(gè)Bean實(shí)現(xiàn)了BeanFactoryAware接口,會(huì)調(diào)用它實(shí)現(xiàn)的setBeanFactory()方法,傳遞的是Spring工廠自身。
③如果這個(gè)Bean實(shí)現(xiàn)了ApplicationContextAware接口,會(huì)調(diào)用setApplicationContext(ApplicationContext)方法,傳入Spring上下文;
(4)BeanPostProcessor前置處理:如果想對(duì)Bean進(jìn)行一些自定義的前置處理,那么可以讓Bean實(shí)現(xiàn)了BeanPostProcessor接口,那將會(huì)調(diào)用postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean:如果Bean實(shí)現(xiàn)了InitializingBean接口,執(zhí)行afeterPropertiesSet()方法。
(6)init-method:如果Bean在Spring配置文件中配置了 init-method 屬性,則會(huì)自動(dòng)調(diào)用其配置的初始化方法。
(7)BeanPostProcessor后置處理:如果這個(gè)Bean實(shí)現(xiàn)了BeanPostProcessor接口,將會(huì)調(diào)用postProcessAfterInitialization(Object obj, String s)方法;由于這個(gè)方法是在Bean初始化結(jié)束時(shí)調(diào)用的,所以可以被應(yīng)用于內(nèi)存或緩存技術(shù);
以上幾個(gè)步驟完成后,Bean就已經(jīng)被正確創(chuàng)建了,之后就可以使用這個(gè)Bean了。
(8)DisposableBean:當(dāng)Bean不再需要時(shí),會(huì)經(jīng)過(guò)清理階段,如果Bean實(shí)現(xiàn)了DisposableBean這個(gè)接口,會(huì)調(diào)用其實(shí)現(xiàn)的destroy()方法;
(9)destroy-method:最后,如果這個(gè)Bean的Spring配置中配置了destroy-method屬性,會(huì)自動(dòng)調(diào)用其配置的銷毀方法。
如果對(duì)bean詳細(xì)加載流程的感興趣的讀者,可以閱讀這篇文章:https://blog.csdn.net/a745233700/article/details/113840727
10、 Spring中bean的作用域:
(1)singleton:默認(rèn)作用域,單例bean,每個(gè)容器中只有一個(gè)bean的實(shí)例。
(2)prototype:為每一個(gè)bean請(qǐng)求創(chuàng)建一個(gè)實(shí)例。
(3)request:為每一個(gè)request請(qǐng)求創(chuàng)建一個(gè)實(shí)例,在請(qǐng)求完成以后,bean會(huì)失效并被垃圾回收器回收。
(4)session:與request范圍類似,同一個(gè)session會(huì)話共享一個(gè)實(shí)例,不同會(huì)話使用不同的實(shí)例。
(5)global-session:全局作用域,所有會(huì)話共享一個(gè)實(shí)例。如果想要聲明讓所有會(huì)話共享的存儲(chǔ)變量的話,那么這全局變量需要存儲(chǔ)在global-session中。
11、Spring框架中的Bean是線程安全的么?如果線程不安全,那么如何處理?
Spring容器本身并沒(méi)有提供Bean的線程安全策略,因此可以說(shuō)Spring容器中的Bean本身不具備線程安全的特性,但是具體情況還是要結(jié)合Bean的作用域來(lái)討論。
(1)對(duì)于prototype作用域的Bean,每次都創(chuàng)建一個(gè)新對(duì)象,也就是線程之間不存在Bean共享,因此不會(huì)有線程安全問(wèn)題。
(2)對(duì)于singleton作用域的Bean,所有的線程都共享一個(gè)單例實(shí)例的Bean,因此是存在線程安全問(wèn)題的。但是如果單例Bean是一個(gè)無(wú)狀態(tài)Bean,也就是線程中的操作不會(huì)對(duì)Bean的成員執(zhí)行查詢以外的操作,那么這個(gè)單例Bean是線程安全的。比如Controller類、Service類和Dao等,這些Bean大多是無(wú)狀態(tài)的,只關(guān)注于方法本身。
有狀態(tài)Bean(Stateful Bean) :就是有實(shí)例變量的對(duì)象,可以保存數(shù)據(jù),是非線程安全的。
無(wú)狀態(tài)Bean(Stateless Bean):就是沒(méi)有實(shí)例變量的對(duì)象,不能保存數(shù)據(jù),是不變類,是線程安全的。
對(duì)于有狀態(tài)的bean(比如Model和View),就需要自行保證線程安全,最淺顯的解決辦法就是將有狀態(tài)的bean的作用域由“singleton”改為“prototype”。
也可以采用ThreadLocal解決線程安全問(wèn)題,為每個(gè)線程提供一個(gè)獨(dú)立的變量副本,不同線程只操作自己線程的副本變量。
ThreadLocal和線程同步機(jī)制都是為了解決多線程中相同變量的訪問(wèn)沖突問(wèn)題。同步機(jī)制采用了“時(shí)間換空間”的方式,僅提供一份變量,不同的線程在訪問(wèn)前需要獲取鎖,沒(méi)獲得鎖的線程則需要排隊(duì)。而ThreadLocal采用了“空間換時(shí)間”的方式。ThreadLocal會(huì)為每一個(gè)線程提供一個(gè)獨(dú)立的變量副本,從而隔離了多個(gè)線程對(duì)數(shù)據(jù)的訪問(wèn)沖突。因?yàn)槊恳粋€(gè)線程都擁有自己的變量副本,從而也就沒(méi)有必要對(duì)該變量進(jìn)行同步了。
12、Spring基于xml注入bean的幾種方式:
詳細(xì)內(nèi)容請(qǐng)參考這篇文章:Spring中bean的注入方式
13、Spring如何解決循環(huán)依賴問(wèn)題:
詳細(xì)內(nèi)容強(qiáng)烈建議參考這篇文章:Spring如何解決循環(huán)依賴問(wèn)題
循環(huán)依賴問(wèn)題在Spring中主要有三種情況:
(1)通過(guò)構(gòu)造方法進(jìn)行依賴注入時(shí)產(chǎn)生的循環(huán)依賴問(wèn)題。
(2)通過(guò)setter方法進(jìn)行依賴注入且是在多例(原型)模式下產(chǎn)生的循環(huán)依賴問(wèn)題。
(3)通過(guò)setter方法進(jìn)行依賴注入且是在單例模式下產(chǎn)生的循環(huán)依賴問(wèn)題。
在Spring中,只有第(3)種方式的循環(huán)依賴問(wèn)題被解決了,其他兩種方式在遇到循環(huán)依賴問(wèn)題時(shí)都會(huì)產(chǎn)生異常。這是因?yàn)椋?/span>
第一種構(gòu)造方法注入的情況下,在new對(duì)象的時(shí)候就會(huì)堵塞住了,其實(shí)也就是”先有雞還是先有蛋“的歷史難題。
第二種setter方法(多例)的情況下,每一次getBean()時(shí),都會(huì)產(chǎn)生一個(gè)新的Bean,如此反復(fù)下去就會(huì)有無(wú)窮無(wú)盡的Bean產(chǎn)生了,最終就會(huì)導(dǎo)致OOM問(wèn)題的出現(xiàn)。
Spring在單例模式下的setter方法依賴注入引起的循環(huán)依賴問(wèn)題,主要是通過(guò)二級(jí)緩存和三級(jí)緩存來(lái)解決的,其中三級(jí)緩存是主要功臣。解決的核心原理就是:在對(duì)象實(shí)例化之后,依賴注入之前,Spring提前暴露的Bean實(shí)例的引用在第三級(jí)緩存中進(jìn)行存儲(chǔ)。
14、Spring的自動(dòng)裝配:
在spring中,使用autowire來(lái)配置自動(dòng)裝載模式,對(duì)象無(wú)需自己查找或創(chuàng)建與其關(guān)聯(lián)的其他對(duì)象,由容器負(fù)責(zé)把需要相互協(xié)作的對(duì)象引用賦予各個(gè)對(duì)象。
(1)在Spring框架xml配置中共有5種自動(dòng)裝配:
no:默認(rèn)的方式是不進(jìn)行自動(dòng)裝配的,通過(guò)手工設(shè)置ref屬性來(lái)進(jìn)行裝配bean。
byName:通過(guò)bean的名稱進(jìn)行自動(dòng)裝配,如果一個(gè)bean的 property 與另一bean 的name 相同,就進(jìn)行自動(dòng)裝配。
byType:通過(guò)參數(shù)的數(shù)據(jù)類型進(jìn)行自動(dòng)裝配。
constructor:利用構(gòu)造函數(shù)進(jìn)行裝配,并且構(gòu)造函數(shù)的參數(shù)通過(guò)byType進(jìn)行裝配。
autodetect:自動(dòng)探測(cè),如果有構(gòu)造方法,通過(guò) construct的方式自動(dòng)裝配,否則使用 byType的方式自動(dòng)裝配。
(2)基于注解的自動(dòng)裝配方式:
使用@Autowired、@Resource注解來(lái)自動(dòng)裝配指定的bean。在使用@Autowired注解之前需要在Spring配置文件進(jìn)行配置,<context:annotation-config />。在啟動(dòng)spring IoC時(shí),容器自動(dòng)裝載了一個(gè)AutowiredAnnotationBeanPostProcessor后置處理器,當(dāng)容器掃描到@Autowied、@Resource或@Inject時(shí),就會(huì)在IoC容器自動(dòng)查找需要的bean,并裝配給該對(duì)象的屬性。在使用@Autowired時(shí),首先在容器中查詢對(duì)應(yīng)類型的bean:
如果查詢結(jié)果剛好為一個(gè),就將該bean裝配給@Autowired指定的數(shù)據(jù);
如果查詢的結(jié)果不止一個(gè),那么@Autowired會(huì)根據(jù)名稱來(lái)查找;
如果上述查找的結(jié)果為空,那么會(huì)拋出異常。解決方法時(shí),使用required=false。
@Autowired可用于:構(gòu)造函數(shù)、成員變量、Setter方法
注:@Autowired和@Resource之間的區(qū)別:
(1) @Autowired默認(rèn)是按照類型裝配注入的,默認(rèn)情況下它要求依賴對(duì)象必須存在(可以設(shè)置它required屬性為false)。
(2) @Resource默認(rèn)是按照名稱來(lái)裝配注入的,只有當(dāng)找不到與名稱匹配的bean才會(huì)按照類型來(lái)裝配注入。
15、Spring事務(wù)的實(shí)現(xiàn)方式和實(shí)現(xiàn)原理:
Spring事務(wù)的本質(zhì)其實(shí)就是數(shù)據(jù)庫(kù)對(duì)事務(wù)的支持,沒(méi)有數(shù)據(jù)庫(kù)的事務(wù)支持,spring是無(wú)法提供事務(wù)功能的。Spring只提供統(tǒng)一事務(wù)管理接口,具體實(shí)現(xiàn)都是由各數(shù)據(jù)庫(kù)自己實(shí)現(xiàn),數(shù)據(jù)庫(kù)事務(wù)的提交和回滾是通過(guò)binlog或者undo log實(shí)現(xiàn)的。Spring會(huì)在事務(wù)開(kāi)始時(shí),根據(jù)當(dāng)前環(huán)境中設(shè)置的隔離級(jí)別,調(diào)整數(shù)據(jù)庫(kù)隔離級(jí)別,由此保持一致。
(1)Spring事務(wù)的種類:
spring支持編程式事務(wù)管理和聲明式事務(wù)管理兩種方式:
①編程式事務(wù)管理使用TransactionTemplate。
②聲明式事務(wù)管理建立在AOP之上的。其本質(zhì)是通過(guò)AOP功能,對(duì)方法前后進(jìn)行攔截,將事務(wù)處理的功能編織到攔截的方法中,也就是在目標(biāo)方法開(kāi)始之前啟動(dòng)一個(gè)事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù)。
聲明式事務(wù)最大的優(yōu)點(diǎn)就是不需要在業(yè)務(wù)邏輯代碼中摻雜事務(wù)管理的代碼,只需在配置文件中做相關(guān)的事務(wù)規(guī)則聲明或通過(guò)@Transactional注解的方式,便可以將事務(wù)規(guī)則應(yīng)用到業(yè)務(wù)邏輯中,減少業(yè)務(wù)代碼的污染。唯一不足地方是,最細(xì)粒度只能作用到方法級(jí)別,無(wú)法做到像編程式事務(wù)那樣可以作用到代碼塊級(jí)別。
(2)spring的事務(wù)傳播機(jī)制:
spring事務(wù)的傳播機(jī)制說(shuō)的是,當(dāng)多個(gè)事務(wù)同時(shí)存在的時(shí)候,spring如何處理這些事務(wù)的行為。事務(wù)傳播機(jī)制實(shí)際上是使用簡(jiǎn)單的ThreadLocal實(shí)現(xiàn)的,所以,如果調(diào)用的方法是在新線程調(diào)用的,事務(wù)傳播實(shí)際上是會(huì)失效的。
① PROPAGATION_REQUIRED:(默認(rèn)傳播行為)如果當(dāng)前沒(méi)有事務(wù),就創(chuàng)建一個(gè)新事務(wù);如果當(dāng)前存在事務(wù),就加入該事務(wù)。
② PROPAGATION_REQUIRES_NEW:無(wú)論當(dāng)前存不存在事務(wù),都創(chuàng)建新事務(wù)進(jìn)行執(zhí)行。
③ PROPAGATION_SUPPORTS:如果當(dāng)前存在事務(wù),就加入該事務(wù);如果當(dāng)前不存在事務(wù),就以非事務(wù)執(zhí)行。‘
④ PROPAGATION_NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
⑤ PROPAGATION_NESTED:如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行;如果當(dāng)前沒(méi)有事務(wù),則按REQUIRED屬性執(zhí)行。
⑥ PROPAGATION_MANDATORY:如果當(dāng)前存在事務(wù),就加入該事務(wù);如果當(dāng)前不存在事務(wù),就拋出異常。
⑦ PROPAGATION_NEVER:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
(3)Spring中的隔離級(jí)別:
① ISOLATION_DEFAULT:這是個(gè) PlatfromTransactionManager 默認(rèn)的隔離級(jí)別,使用數(shù)據(jù)庫(kù)默認(rèn)的事務(wù)隔離級(jí)別。
② ISOLATION_READ_UNCOMMITTED:讀未提交,允許事務(wù)在執(zhí)行過(guò)程中,讀取其他事務(wù)未提交的數(shù)據(jù)。
③ ISOLATION_READ_COMMITTED:讀已提交,允許事務(wù)在執(zhí)行過(guò)程中,讀取其他事務(wù)已經(jīng)提交的數(shù)據(jù)。
④ ISOLATION_REPEATABLE_READ:可重復(fù)讀,在同一個(gè)事務(wù)內(nèi),任意時(shí)刻的查詢結(jié)果都是一致的。
⑤ ISOLATION_SERIALIZABLE:所有事務(wù)逐個(gè)依次執(zhí)行。
16、Spring 框架中都用到了哪些設(shè)計(jì)模式?
Spring設(shè)計(jì)模式的詳細(xì)使用案例可以閱讀這篇文章:https://blog.csdn.net/a745233700/article/details/112598471
(1)工廠模式:Spring使用工廠模式,通過(guò)BeanFactory和ApplicationContext來(lái)創(chuàng)建對(duì)象
(2)單例模式:Bean默認(rèn)為單例模式
(3)策略模式:例如Resource的實(shí)現(xiàn)類,針對(duì)不同的資源文件,實(shí)現(xiàn)了不同方式的資源獲取策略
(4)代理模式:Spring的AOP功能用到了JDK的動(dòng)態(tài)代理和CGLIB字節(jié)碼生成技術(shù)
(5)模板方法:可以將相同部分的代碼放在父類中,而將不同的代碼放入不同的子類中,用來(lái)解決代碼重復(fù)的問(wèn)題。比如RestTemplate, JmsTemplate, JpaTemplate
(6)適配器模式:Spring AOP的增強(qiáng)或通知(Advice)使用到了適配器模式,Spring MVC中也是用到了適配器模式適配Controller
(7)觀察者模式:Spring事件驅(qū)動(dòng)模型就是觀察者模式的一個(gè)經(jīng)典應(yīng)用。
(8)橋接模式:可以根據(jù)客戶的需求能夠動(dòng)態(tài)切換不同的數(shù)據(jù)源。比如我們的項(xiàng)目需要連接多個(gè)數(shù)據(jù)庫(kù),客戶在每次訪問(wèn)中根據(jù)需要會(huì)去訪問(wèn)不同的數(shù)據(jù)庫(kù)
17、Spring框架中有哪些不同類型的事件?
Spring 提供了以下5種標(biāo)準(zhǔn)的事件:
(1)上下文更新事件(ContextRefreshedEvent):在調(diào)用ConfigurableApplicationContext 接口中的refresh()方法時(shí)被觸發(fā)。
(2)上下文開(kāi)始事件(ContextStartedEvent):當(dāng)容器調(diào)用ConfigurableApplicationContext的Start()方法開(kāi)始/重新開(kāi)始容器時(shí)觸發(fā)該事件。
(3)上下文停止事件(ContextStoppedEvent):當(dāng)容器調(diào)用ConfigurableApplicationContext的Stop()方法停止容器時(shí)觸發(fā)該事件。
(4)上下文關(guān)閉事件(ContextClosedEvent):當(dāng)ApplicationContext被關(guān)閉時(shí)觸發(fā)該事件。容器被關(guān)閉時(shí),其管理的所有單例Bean都被銷毀。
(5)請(qǐng)求處理事件(RequestHandledEvent):在Web應(yīng)用中,當(dāng)一個(gè)http請(qǐng)求(request)結(jié)束觸發(fā)該事件。
如果一個(gè)bean實(shí)現(xiàn)了ApplicationListener接口,當(dāng)一個(gè)ApplicationEvent 被發(fā)布以后,bean會(huì)自動(dòng)被通知。
版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接和本聲明。
本文鏈接:
https://blog.csdn.net/a745233700/article/details/80959716
