<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring常見(jiàn)面試題總結(jié)(超詳細(xì)回答)

          共 13413字,需瀏覽 27分鐘

           ·

          2021-06-19 20:34

          點(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í)行順序:

          • around before advice

          • before advice

          • target method 執(zhí)行

          • around after advice

          • after advice

          • afterThrowing

          • java.lang.RuntimeException: 異常發(fā)生 

          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的幾種方式:

          • set()方法注入;

          • 構(gòu)造器注入:①通過(guò)index設(shè)置參數(shù)的位置;②通過(guò)type設(shè)置參數(shù)類型;

          • 靜態(tài)工廠注入;

          • 實(shí)例工廠;

          詳細(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










          瀏覽 91
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  综合网激情 | 超碰操操操 | 青青草青青日青青干视频 | 最新国产亚洲免费在线视频 | 黄色视频操逼 |