Spring面試題
Spring面試題
1.談?wù)勀銓?duì)Spring的理解?
- Spring是一個(gè)輕量級(jí)Java開(kāi)發(fā)框架,目的是為了解決企業(yè)級(jí)應(yīng)用開(kāi)發(fā)的業(yè)務(wù)邏輯層和其他各層的耦合問(wèn)題。它是一個(gè)分層的JavaSE/JavaEE full-stack(一站式)輕量級(jí)
開(kāi)源框架,為開(kāi)發(fā)Java應(yīng)用程序提供全面的基礎(chǔ)架構(gòu)支持。Spring負(fù)責(zé)基礎(chǔ)架構(gòu),因此Java開(kāi)發(fā)者可以專(zhuān)注于應(yīng)用程序的開(kāi)發(fā)。
- Spring最根本的使命是解決企業(yè)級(jí)應(yīng)用開(kāi)發(fā)的復(fù)雜性,即簡(jiǎn)化Java開(kāi)發(fā)。Spring可以做很多事情,它為企業(yè)級(jí)開(kāi)發(fā)提供給了豐富的功能,但是這些功能的底層都依賴于它的
兩個(gè)核心特性,也就是依賴注入(dependency injection,DI)和面向切面編程(aspectoriented programming,AOP)。
2.什么是SpringIOC?
- IOC即控制反轉(zhuǎn),Inversion of Control,把傳統(tǒng)的由程序代碼直接操控的對(duì)象調(diào)用權(quán)交給Spring容器,通過(guò)容器實(shí)現(xiàn)對(duì)象的組件的裝配和管理。所謂控制反轉(zhuǎn),就是對(duì)組件對(duì)象控制權(quán)的轉(zhuǎn)移,從程序代碼轉(zhuǎn)移到了外部容器
- Spring IOC負(fù)責(zé)創(chuàng)建對(duì)象,管理對(duì)象,通過(guò)依賴注入,裝配對(duì)象,配置對(duì)象,并管理對(duì)象的整個(gè)生命周期對(duì) IOC來(lái)說(shuō),最重要的就是容器,容器管理Bean的生命周期,控制Bean的依賴注入
IOC有什么用?
- 管理對(duì)象的創(chuàng)建和依賴關(guān)系的維護(hù)。
- 解耦,由容器去維護(hù)具體的對(duì)象
- 托管了類(lèi)的產(chǎn)生過(guò)程,比如我們需要在類(lèi)的產(chǎn)生過(guò)程做一些處理,比如代理,如果有容器就可以吧這部分交給容器,應(yīng)用程序則無(wú)需關(guān)心如何完成代理的
舉例
UserService userService = newUserService() //耦合度太高,維護(hù)不方便
引入IOC,就是將創(chuàng)建對(duì)象的控制權(quán)交給Spring容器,以前由程序員自己創(chuàng)建,現(xiàn)在交給SpringIOC去創(chuàng)建,使用的時(shí)候就可以通過(guò)DI(@Autowired)去使用,而且默認(rèn)是單例的
IOC的優(yōu)點(diǎn)?
- 最小的代價(jià)和最小的侵入性使得松散耦合得以實(shí)現(xiàn)
- IOC容器支持加載服務(wù)時(shí)的餓漢式加載和懶漢式加載
IOC的實(shí)現(xiàn)機(jī)制是什么:工廠+反射
3.Spring的優(yōu)缺點(diǎn)是什么?
優(yōu)點(diǎn)
- 方便解耦,簡(jiǎn)化開(kāi)發(fā)
Spring就是一個(gè)大工廠,可以將所有對(duì)象的創(chuàng)建和依賴關(guān)系的維護(hù),交給Spring管理。
- AOP編程的支持
Spring提供面向切面編程,可以方便的實(shí)現(xiàn)對(duì)程序進(jìn)行權(quán)限攔截、運(yùn)行監(jiān)控等功能。
- 聲明式事務(wù)的支持
只需要通過(guò)配置就可以完成對(duì)事務(wù)的管理,而無(wú)需手動(dòng)編程。
- 方便程序的測(cè)試
Spring對(duì)Junit4支持,可以通過(guò)注解方便的測(cè)試Spring程序。
- 方便集成各種優(yōu)秀框架
Spring不排斥各種優(yōu)秀的開(kāi)源框架,其內(nèi)部提供了對(duì)各種優(yōu)秀框架的直接支持(如:Struts、
Hibernate、MyBatis等)。
- 降低JavaEE API的使用難度
Spring對(duì)JavaEE開(kāi)發(fā)中非常難用的一些API(JDBC、JavaMail、遠(yuǎn)程調(diào)用等),都提供了封裝,使
這些API應(yīng)用難度大大降低。
缺點(diǎn)
- Spring明明一個(gè)很輕量級(jí)的框架,卻給人感覺(jué)大而全
- Spring依賴反射,反射影響性能
- 使用門(mén)檻升高,入門(mén)Spring需要較長(zhǎng)時(shí)間
4.Spring 框架中都用到了哪些設(shè)計(jì)模式?
- 工廠模式:BeanFactory就是簡(jiǎn)單工廠模式的體現(xiàn),用來(lái)創(chuàng)建對(duì)象的實(shí)例;
- 單例模式:Bean默認(rèn)為單例模式。
- 代理模式:Spring的AOP功能用到了JDK的動(dòng)態(tài)代理和CGLIB字節(jié)碼生成技術(shù);
- 模板方法:用來(lái)解決代碼重復(fù)的問(wèn)題。比如. RestTemplate, JmsTemplate, JpaTemplate。
- 觀察者模式:定義對(duì)象鍵一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都會(huì)得到通知被制動(dòng)更新,如Spring中l(wèi)istener的實(shí)現(xiàn)–ApplicationListener。
5.ApplicationContext 和BeanFactory的區(qū)別?
BeanFactory是Spring的核心組件,BeanFactory是Spring里面最底層的接口,定義了Ioc的基本功能,包含各種Bean的定義、
加載、實(shí)例化,依賴注入和生命周期管理;而ApplicationContext是BeanFactory的子接口。
ApplicationContext接口作為BeanFactory的子類(lèi),除了提供BeanFactory所具有的功能外,還提供了更完整的框架功能:
①繼承MessageSource,因此支持國(guó)際化
②資源文件訪問(wèn),如URL和文件(ResourceLoader)
3提供在監(jiān)聽(tīng)器中注冊(cè)bean的事件;
6.ApplicationContext通常的實(shí)現(xiàn)是什么?
- FileSystemXmlApplicationContext :此容器從一個(gè)XML文件中加載beans的定義,XML Bean配置文件的全路徑名必須提供給它的構(gòu)造函數(shù)。
- ClassPathXmlApplicationContext:此容器也從一個(gè)XML文件中加載beans的定義,這里,你需要正確設(shè)置classpath因?yàn)檫@個(gè)容器將在classpath里找bean配置。
- WebXmlApplicationContext:此容器加載一個(gè)XML文件,此文件定義了一個(gè)WEB應(yīng)用的所有bean。
7.什么是Spring的依賴注入?
依賴注入(Dependency Injection),簡(jiǎn)稱(chēng)DI,類(lèi)之間的依賴關(guān)系由容器來(lái)負(fù)責(zé)。簡(jiǎn)單來(lái)講a依賴b,但a不創(chuàng)建(或銷(xiāo)毀)b,僅使用b,b的創(chuàng)建(或銷(xiāo)毀)交給容器。
8.有哪些不同類(lèi)型的依賴注入實(shí)現(xiàn)方式?
依賴注入是時(shí)下最流行的IOC實(shí)現(xiàn)方式,依賴注入分為接口注入(Interface Injection),Setter方法注入(Setter Injection)和構(gòu)造器注入(Constructor Injection)三種方式。其中接口注入由于
在靈活性和易用性比較差,現(xiàn)在從Spring4開(kāi)始已被廢棄。
- 構(gòu)造器依賴注入:構(gòu)造器依賴注入通過(guò)容器觸發(fā)一個(gè)類(lèi)的構(gòu)造器來(lái)實(shí)現(xiàn)的,該類(lèi)有一系列參數(shù),每個(gè)參數(shù)代表一個(gè)對(duì)其他類(lèi)的依賴。
- Setter方法注入:Setter方法注入是容器通過(guò)調(diào)用無(wú)參構(gòu)造器或無(wú)參static工廠 方法實(shí)例化bean之后,調(diào)用該bean的setter方法,即實(shí)現(xiàn)了基于setter的依賴注入
9.如何給Spring 容器提供配置元數(shù)據(jù)?Spring有幾種配置方式
- XML配置文件。
- 基于注解的配置。
- 基于java的配置。
10.解釋Spring支持的幾種bean的作用域
Spring框架支持以下五種bean的作用域:
- singleton : bean在每個(gè)Spring ioc 容器中只有一個(gè)實(shí)例。
- prototype:一個(gè)bean的定義可以有多個(gè)實(shí)例。
- request:每次http請(qǐng)求都會(huì)創(chuàng)建一個(gè)bean,該作用域僅在基于web的SpringApplicationContext情形下有效。
- session:在一個(gè)HTTP Session中,一個(gè)bean定義對(duì)應(yīng)一個(gè)實(shí)例。該作用域僅在基于web的Spring ApplicationContext情形下有效。
- global-session:在一個(gè)全局的HTTP Session中,一個(gè)bean定義對(duì)應(yīng)一個(gè)實(shí)例。該作用域僅在基于web的Spring ApplicationContext情形下有效。
11.Spring框架中的單例bean是線程安全的嗎?
- 不是,Spring框架中的單例bean不是線程安全的。
- spring 中的 bean 默認(rèn)是單例模式,spring 框架并沒(méi)有對(duì)單例 bean 進(jìn)行多線程的封裝處理。實(shí)際上大部分時(shí)候 spring bean 無(wú)狀態(tài)的(比如 dao 類(lèi)),
所有某種程度上來(lái)說(shuō) bean 也是安全的,但如果 bean 有狀態(tài)的話(比如 view model 對(duì)象),那就要開(kāi)發(fā)者自己去保證線程安全了,
- 最簡(jiǎn)單的就是改變 bean 的作用域,把“singleton”變更為“prototype”,這樣請(qǐng)求 bean 相當(dāng)于new Bean()了,所以就可以保證線程安全了。
- 有狀態(tài)就是有數(shù)據(jù)存儲(chǔ)功能。
- 無(wú)狀態(tài)就是不會(huì)保存數(shù)據(jù)。
12.Spring如何處理線程并發(fā)問(wèn)題?
- 在一般情況下,只有無(wú)狀態(tài)的Bean才可以在多線程環(huán)境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域,因?yàn)镾pring對(duì)一些Bean中非線程安全狀態(tài)采用ThreadLocal進(jìn)行處
理,解決線程安全問(wèn)題。
- 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)行同步了。ThreadLocal提
供了線程安全的共享對(duì)象,在編寫(xiě)多線程代碼時(shí),可以把不安全的變量封裝進(jìn)ThreadLocal。
13.Spring框架中bean的生命周期
- 1.實(shí)例化
-- 通過(guò)反射推斷構(gòu)造函數(shù)進(jìn)行實(shí)例化
- 2.屬性賦值
-- 解析自動(dòng)裝配,DI的體現(xiàn)
-- 循環(huán)依賴的解決
- 3.初始化
-- 調(diào)用很多的--Aware,比如BeanNameAware,BeanClassLoaderAware的回調(diào)方法
-- 調(diào)用初始化生命周期的回調(diào)
-- 如果Bean實(shí)現(xiàn)了AOP,那么創(chuàng)建動(dòng)態(tài)代理
- 4.銷(xiāo)毀
-- 在Spring容器關(guān)閉的時(shí)候進(jìn)行調(diào)用
14.什么是bean的自動(dòng)裝配?
意思就是spring會(huì)在上下文中自動(dòng)尋找,并自動(dòng)給bean裝配屬性。
15.spring 自動(dòng)裝配 bean 有哪些方式?
在spring中,對(duì)象無(wú)需自己查找或創(chuàng)建與其關(guān)聯(lián)的其他對(duì)象,由容器負(fù)責(zé)把需要相互協(xié)作的對(duì)象引用賦予各個(gè)對(duì)象,使用autowire來(lái)配置自動(dòng)裝載模式。
在Spring框架xml配置中共有5種自動(dòng)裝配:
- no:默認(rèn)的方式是不進(jìn)行自動(dòng)裝配的,通過(guò)手工設(shè)置ref屬性來(lái)進(jìn)行裝配bean。
- byName:通過(guò)bean的名稱(chēng)進(jìn)行自動(dòng)裝配,如果一個(gè)bean的 property 與另一bean 的name 相同,就進(jìn)行自動(dòng)裝配。
- byType:通過(guò)參數(shù)的數(shù)據(jù)類(lèi)型進(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)裝配。
16.@Autowired注解自動(dòng)裝配的過(guò)程是怎樣的?
- 使用@Autowired注解來(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)類(lèi)型的bean:如果查詢結(jié)果剛好為一個(gè),就將該bean裝配給@Autowired指定的數(shù)據(jù);
- 如果查詢的結(jié)果不止一個(gè),那么@Autowired會(huì)根據(jù)名稱(chēng)來(lái)查找;如果上述查找的結(jié)果為空,那么會(huì)拋出異常。解決方法時(shí),使用required=false。
17.什么是基于Java的Spring注解配置?
- 基于Java的配置,允許你在少量的Java注解的幫助下,進(jìn)行你的大部分Spring配置而非通過(guò)XML文件。
- 以@Configuration 注解為例,Component注解表明一個(gè)類(lèi)會(huì)作為組件類(lèi),并告知Spring要為這個(gè)類(lèi)創(chuàng)建bean,相當(dāng)于之前寫(xiě)的xml文件。
- 另一個(gè)例子是@Bean注解,它表示此方法將要返回一個(gè)對(duì)象,作為一個(gè)bean注冊(cè)進(jìn)Spring應(yīng)用上下文,相當(dāng)在xml中定義Bean標(biāo)簽。
18.@Component, @Controller, @Repository, @Service 有何區(qū)別?
- @Component:這將 java 類(lèi)標(biāo)記為 bean。它是任何 Spring 管理組件的通用構(gòu)造型。spring 的組件掃描機(jī)制現(xiàn)在可以將其拾取并將其拉入應(yīng)用程序環(huán)境中。
- @Controller:這將一個(gè)類(lèi)標(biāo)記為 Spring Web MVC 控制器。標(biāo)有它的 Bean 會(huì)自動(dòng)導(dǎo)入到 IOC 容器中。
- @Service:此注解是組件注解的特化。它不會(huì)對(duì) @Component 注解提供任何其他行為。您可以在服務(wù)層類(lèi)中使用 @Service 而不是 @Component,因?yàn)樗愿玫姆绞街付艘鈭D。
- @Repository:這個(gè)注解是具有類(lèi)似用途和功能的 @Component 注解的特化。它為 DAO 提供了額外的好處。它將 DAO 導(dǎo)入 IOC 容器,并使未經(jīng)檢查的異常有資格轉(zhuǎn)換為 Spring
DataAccessException。
19.@Autowired 注解有什么作用
@Autowired默認(rèn)是按照類(lèi)型裝配注入的,默認(rèn)情況下它要求依賴對(duì)象必須存在(可以設(shè)置它required屬性為false)。@Autowired 注解提供了更細(xì)粒度的控制,
包括在何處以及如何完成自動(dòng)裝配。它的用法和@Required一樣,修飾setter方法、構(gòu)造器、屬性或者具有任意名稱(chēng)和/或多個(gè)參數(shù)的PN方法。
20.@Autowired和@Resource之間的區(qū)別
@Autowired和@Resource之間的區(qū)別在于
- @Autowired默認(rèn)是按照類(lèi)型裝配注入的,默認(rèn)情況下它要求依賴對(duì)象必須存在(可以設(shè)置它required屬性為false)
- @Resource默認(rèn)是按照名稱(chēng)來(lái)裝配注入的,只有當(dāng)找不到與名稱(chēng)匹配的bean才會(huì)按照類(lèi)型來(lái)裝配注入。
21.Spring的事務(wù)傳播行為
- ① PROPAGATION_REQUIRED:如果當(dāng)前沒(méi)有事務(wù),就創(chuàng)建一個(gè)新事務(wù),如果當(dāng)前存在事務(wù),就 加入該事務(wù),該設(shè)置是最常用的設(shè)置。
- ② PROPAGATION_SUPPORTS:支持當(dāng)前事務(wù),如果當(dāng)前存在事務(wù),就加入該事務(wù),如果當(dāng)前不 存在事務(wù),就以非事務(wù)執(zhí)行。
- ③ PROPAGATION_MANDATORY:支持當(dāng)前事務(wù),如果當(dāng)前存在事務(wù),就加入該事務(wù),如果當(dāng)前 不存在事務(wù),就拋出異常。
- ④ PROPAGATION_REQUIRES_NEW:創(chuàng)建新事務(wù),無(wú)論當(dāng)前存不存在事務(wù),都創(chuàng)建新事務(wù)。
- ⑤ PROPAGATION_NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前 事務(wù)掛起。
- ⑥ PROPAGATION_NEVER:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
- ⑦ PROPAGATION_NESTED:如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒(méi)有事務(wù),則 按REQUIRED屬性執(zhí)行。
22.spring 的事務(wù)隔離?
spring 有五大隔離級(jí)別,默認(rèn)值為 ISOLATION_DEFAULT(使用數(shù)據(jù)庫(kù)的設(shè)置),其他四個(gè)隔離
級(jí)別和數(shù)據(jù)庫(kù)的隔離級(jí)別一致:
1.ISOLATION_DEFAULT:用底層數(shù)據(jù)庫(kù)的設(shè)置隔離級(jí)別,數(shù)據(jù)庫(kù)設(shè)置的是什么我就用什么;
2.ISOLATION_READ_UNCOMMITTED:未提交讀,最低隔離級(jí)別、事務(wù)未提交前,就可被其他事務(wù)讀取(會(huì)出現(xiàn)幻讀、臟讀、不可重復(fù)讀);
3.ISOLATION_READ_COMMITTED:提交讀,一個(gè)事務(wù)提交后才能被其他事務(wù)讀取到(會(huì)造成幻讀、不可重復(fù)讀),SQL server 的默認(rèn)級(jí)別;
4.ISOLATION_REPEATABLE_READ:可重復(fù)讀,保證多次讀取同一個(gè)數(shù)據(jù)時(shí),其值都和事務(wù)開(kāi)始時(shí)候的內(nèi)容是一致,禁止讀取到別的事務(wù)未提交的數(shù)據(jù)(會(huì)造成幻讀),MySQL 的默認(rèn)級(jí)別;
5.ISOLATION_SERIALIZABLE:序列化,代價(jià)最高最可靠的隔離級(jí)別,該隔離級(jí)別能防止臟讀、不可重復(fù)讀、幻讀。
23.什么是AOP?有哪些實(shí)現(xiàn)方式?
AOP實(shí)現(xiàn)的關(guān)鍵在于 代理模式,AOP代理主要分為靜態(tài)代理和動(dòng)態(tài)代理。靜態(tài)代理的代表為AspectJ;動(dòng)態(tài)代理則以Spring AOP為代表。
- AspectJ是靜態(tài)代理的增強(qiáng),所謂靜態(tài)代理,就是AOP框架會(huì)在編譯階段生成AOP代理類(lèi),因此也稱(chēng)為編譯時(shí)增強(qiáng),他會(huì)在編譯階段將AspectJ(切面)織入到Java字節(jié)碼中,運(yùn)行的時(shí)候就是增強(qiáng)之后的AOP對(duì)象。
- 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)代理只提供接口的代理,不支持類(lèi)的代理。核心InvocationHandler接口和Proxy類(lèi),InvocationHandler 通過(guò)invoke()方法反射來(lái)調(diào)用目標(biāo)類(lèi)中的代碼,動(dòng)態(tài)地將橫切邏輯和
業(yè)務(wù)編織在一起;接著,Proxy利用 InvocationHandler動(dòng)態(tài)創(chuàng)建一個(gè)符合某一接口的的實(shí)例, 生成目標(biāo)類(lèi)的代理對(duì)象。
- 如果代理類(lèi)沒(méi)有實(shí)現(xiàn) InvocationHandler 接口,那么Spring AOP會(huì)選擇使用CGLIB來(lái)動(dòng)態(tài)代理目標(biāo)類(lèi)。
- CGLIB(Code Generation Library),是一個(gè)代碼生成的類(lèi)庫(kù),可以在運(yùn)行時(shí)動(dòng)態(tài)的生成指定類(lèi)的一個(gè)子類(lèi)對(duì)象,并覆蓋其中特定方法并添加增強(qiáng)代碼,從而實(shí)現(xiàn)AOP。CGLIB是通過(guò)繼承的方式做的動(dòng)態(tài)代理,
因此如果某個(gè)類(lèi)被標(biāo)記為final,那么它是無(wú)法使用CGLIB做動(dòng)態(tài)代理的。
靜態(tài)代理與動(dòng)態(tài)代理區(qū)別在于生成AOP代理對(duì)象的時(shí)機(jī)不同,相對(duì)來(lái)說(shuō)AspectJ的靜態(tài)代理方式具有更好的性能,但是AspectJ需要特定的編譯器進(jìn)行處理,而Spring AOP則無(wú)需特定的編譯器處理。
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最終生成的代理實(shí)例; method 是被代理目標(biāo)實(shí)例的某個(gè)具體方法; args 是被代理目標(biāo)實(shí)例某個(gè)方法的具體
入?yún)? 在方法反射調(diào)用時(shí)使用。
24.Spring AOP里面的幾個(gè)名詞
(1)切面(Aspect):切面是通知和切點(diǎn)的結(jié)合。通知和切點(diǎn)共同定義了切面的全部?jī)?nèi)容。 在Spring AOP中,切面可以使用通用類(lèi)(基于模式的風(fēng)格) 或者在普通類(lèi)中以 @AspectJ 注解來(lái)實(shí)現(xiàn)。
(2)連接點(diǎn)(Join point):指方法,在Spring AOP中,一個(gè)連接點(diǎn) 總是 代表一個(gè)方法的執(zhí)行。應(yīng)用可能有數(shù)以千計(jì)的時(shí)機(jī)應(yīng)用通知。這些時(shí)機(jī)被稱(chēng)為連接點(diǎn)。連接點(diǎn)是在應(yīng)用執(zhí)行過(guò)程中能夠插
入切面的一個(gè)點(diǎn)。這個(gè)點(diǎn)可以是調(diào)用方法時(shí)、拋出異常時(shí)、甚至修改一個(gè)字段時(shí)。切面代碼可以利用這些點(diǎn)插入到應(yīng)用的正常流程之中,并添加新的行為。
(3)通知(Advice):在AOP術(shù)語(yǔ)中,切面的工作被稱(chēng)為通知。
(4)切入點(diǎn)(Pointcut):切點(diǎn)的定義會(huì)匹配通知所要織入的一個(gè)或多個(gè)連接點(diǎn)。我們通常使用明確的類(lèi)和方法名稱(chēng),或是利用正則表達(dá)式定義所匹配的類(lèi)和方法名稱(chēng)來(lái)指定這些切點(diǎn)。
(5)引入(Introduction):引入允許我們向現(xiàn)有類(lèi)添加新方法或?qū)傩浴?/span>
(6)目標(biāo)對(duì)象(Target Object): 被一個(gè)或者多個(gè)切面(aspect)所通知(advise)的對(duì)象。它通常是一個(gè)代理對(duì)象。也有人把它叫做 被通知(adviced) 對(duì)象。 既然Spring AOP是通過(guò)運(yùn)行
時(shí)代理實(shí)現(xiàn)的,這個(gè)對(duì)象永遠(yuǎn)是一個(gè) 被代理(proxied) 對(duì)象。
(7)織入(Weaving):織入是把切面應(yīng)用到目標(biāo)對(duì)象并創(chuàng)建新的代理對(duì)象的過(guò)程。在目標(biāo)對(duì)象的生命周期里有多少個(gè)點(diǎn)可以進(jìn)行織入:
25.SpringAOP通知有哪些類(lèi)型?
- 前置通知(Before):在目標(biāo)方法被調(diào)用之前調(diào)用通知功能;
- 后置通知(After):在目標(biāo)方法完成之后調(diào)用通知,此時(shí)不會(huì)關(guān)心方法的輸出是什么;
- 返回通知(After-returning ):在目標(biāo)方法成功執(zhí)行之后調(diào)用通知;
- 異常通知(After-throwing):在目標(biāo)方法拋出異常后調(diào)用通知;
- 環(huán)繞通知(Around):通知包裹了被通知的方法,在被通知的方法調(diào)用之前和調(diào)用之后執(zhí)行自定義的行為。
26.Spring容器的啟動(dòng)流程
- 首先會(huì)進(jìn)行掃描,掃描到所有的BeanDefinition對(duì)象,并存在一個(gè)Map中;
- 然后篩選出非懶加載的單例BeanDefinition進(jìn)行創(chuàng)建Bean,對(duì)于多例Bean不需要在啟動(dòng)時(shí)去創(chuàng)建,而是在每次獲取Bean時(shí)利用BeanDefinition去創(chuàng)建
- 接著利用BeanDefinition創(chuàng)建Bean,即Bean的創(chuàng)建生命周期,期間包括,BeanDefinition,推斷構(gòu)造方法,實(shí)例化,屬性填充,初始化前,初始化,初始化后等步驟,AOP就是發(fā)生在初始化后這一步
- 單例Bean創(chuàng)建完之后,Spring會(huì)發(fā)布一個(gè)容器啟動(dòng)事件
- Spring啟動(dòng)結(jié)束
- Spring啟動(dòng)中還會(huì)去處理@Import等注解
27.哪些情況下會(huì)導(dǎo)致Spring事務(wù)失效?原因是什么
- 方法內(nèi)自調(diào)用:Spring事務(wù)是基于AOP的,只要使用代理對(duì)象調(diào)用某個(gè)方法時(shí),Spring事務(wù)才能生效,而在一個(gè)方法內(nèi)調(diào)用this.method()時(shí),this并不是代理對(duì)象,所以會(huì)導(dǎo)致事務(wù)失效。
解決方法1:把調(diào)用方法拆分到另外一個(gè)Bean中
解決方法2:?jiǎn)⒂聾EnableAspectAutoPorxy(exposeProxy = true)+AopContext.currentProxy()
- 方法是private:Spring事務(wù)會(huì)給予CGLIB進(jìn)行AOP,而CGLIB會(huì)基于繼承父類(lèi)來(lái)實(shí)現(xiàn),如果父類(lèi)中的方法是private,則子類(lèi)中無(wú)法重寫(xiě),也就沒(méi)辦法進(jìn)行Spring的事務(wù)邏輯了
- 方法是final的:原因類(lèi)似,final的方法無(wú)法重寫(xiě)
- 單獨(dú)的線程調(diào)用方法:當(dāng)mybatis或者jdbcTemplate執(zhí)行sql時(shí),會(huì)從ThreadLocal中拿鏈接對(duì)象,如果開(kāi)啟事務(wù)的線程和執(zhí)行sql的是同一個(gè)線程,就能拿到鏈接對(duì)象,
如果不是則拿不到,這樣Mybatis或JDBCTemplate就會(huì)自己新建一個(gè)鏈接去執(zhí)行sql,此數(shù)據(jù)庫(kù)鏈接的autocommit= true,那么執(zhí)行完sql就會(huì)提交,后續(xù)再拋異常也不能回滾之前提交的sql了
- 異常被吃掉:如果Spring事務(wù)沒(méi)有捕獲到異常,就不會(huì)回滾,默認(rèn)Spring會(huì)捕獲RuntimeException和Error
- 類(lèi)沒(méi)有被Spring管理
- 數(shù)據(jù)庫(kù)不支持事務(wù)
28.Spring循環(huán)依賴問(wèn)題
1.什么是循環(huán)依賴問(wèn)題:
- 兩個(gè)或則兩個(gè)以上的對(duì)象互相依賴對(duì)方,最終形成 閉環(huán) 。例如 A 對(duì)象依賴 B 對(duì)象,B 對(duì)象也依賴 A 對(duì)象
2.循環(huán)依賴會(huì)有什么問(wèn)題?
- 對(duì)象的創(chuàng)建過(guò)程會(huì)產(chǎn)生死循環(huán),類(lèi)似如下
3.Spring 是如何解決的呢?
- 通過(guò)三級(jí)緩存提前暴露對(duì)象來(lái)解決的
4.三級(jí)緩存里面分別存的什么?
- 一級(jí)緩存里存的是成品對(duì)象,實(shí)例化和初始化都完成了,我們的應(yīng)用中使用的對(duì)象就是一級(jí)緩存中的
- 二級(jí)緩存中存的是半成品,用來(lái)解決對(duì)象創(chuàng)建過(guò)程中的循環(huán)依賴問(wèn)題
- 三級(jí)緩存中存的是 ObjectFactory<?> 類(lèi)型的 lambda 表達(dá)式,用于處理存在 AOP 時(shí)的循環(huán)依賴問(wèn)題
5.為什么要用三級(jí)緩存來(lái)解決循環(huán)依賴問(wèn)題(只用一級(jí)緩存行不行,只用二級(jí)緩存行不行)
- 只用一級(jí)緩存也是可以解決的,但是會(huì)復(fù)雜化整個(gè)邏輯
- 半成品對(duì)象是沒(méi)法直接使用的(存在 NPE 問(wèn)題),所以 Spring 需要保證在啟動(dòng)的過(guò)程中,所有中間產(chǎn)生的半成品對(duì)象最終都會(huì)變成成品對(duì)象
- 如果將半成品對(duì)象和成品對(duì)象都混在一級(jí)緩存中,那么為了區(qū)分他們,勢(shì)必會(huì)增加一些而外的標(biāo)記和邏輯處理,這就會(huì)導(dǎo)致對(duì)象的創(chuàng)建過(guò)程變得復(fù)雜化了
- 將半成品對(duì)象與成品對(duì)象分開(kāi)存放,兩級(jí)緩存各司其職,能夠簡(jiǎn)化對(duì)象的創(chuàng)建過(guò)程,更簡(jiǎn)單、直觀
- 如果 Spring 不引入 AOP,那么兩級(jí)緩存就夠了,但是作為 Spring 的核心之一,AOP 怎能少得了呢
- 所以為了處理 AOP 時(shí)的循環(huán)依賴,Spring 引入第三級(jí)緩存來(lái)處理循環(huán)依賴時(shí)的代理對(duì)象的創(chuàng)建
6、三級(jí)緩存各自的作用
- 第一級(jí)緩存存的是對(duì)外暴露的對(duì)象,也就是我們應(yīng)用需要用到的
- 第二級(jí)緩存的作用是為了處理循環(huán)依賴的對(duì)象創(chuàng)建問(wèn)題,里面存的是半成品對(duì)象或半成品對(duì)象的代理對(duì)象
- 第三級(jí)緩存的作用處理存在 AOP + 循環(huán)依賴的對(duì)象創(chuàng)建問(wèn)題,能將代理對(duì)象提前創(chuàng)建
7.Spring 為什么要引入第三級(jí)緩存
- 嚴(yán)格來(lái)講,第三級(jí)緩存并非缺它不可,因?yàn)榭梢蕴崆皠?chuàng)建代理對(duì)象
- 提前創(chuàng)建代理對(duì)象只是會(huì)節(jié)省那么一丟丟內(nèi)存空間,并不會(huì)帶來(lái)性能上的提升,但是會(huì)破環(huán) Spring 的設(shè)計(jì)原則
- Spring 的設(shè)計(jì)原則是盡可能保證普通對(duì)象創(chuàng)建完成之后,再生成其 AOP 代理(盡可能延遲代理對(duì)象的生成)
- 所以 Spring 用了第三級(jí)緩存,既維持了設(shè)計(jì)原則,又處理了循環(huán)依賴;犧牲那么一丟丟內(nèi)存空間是愿意接受的.
29.BeanFactory和FactoryBean的區(qū)別
區(qū)別:BeanFactory是個(gè)Factory,也就是IOC容器或?qū)ο??,F(xiàn)actoryBean是個(gè)Bean。在Spring中, 所有的Bean都是由BeanFactory(也就是IOC容器)來(lái)進(jìn)?管理的。
但對(duì)FactoryBean??,這個(gè)Bean不是簡(jiǎn)單的Bean,?是?個(gè)能?產(chǎn)或者修飾對(duì)象?成的??Bean, 它的實(shí)現(xiàn)與設(shè)計(jì)模式中的??模式和修飾器模式類(lèi)似。
BeanFactory,以Factory結(jié)尾,表示它是?個(gè)??類(lèi)(接?), 它負(fù)責(zé)?產(chǎn)和管理bean的?個(gè)??。在 Spring中,BeanFactory是IOC容器的核?接?,它的職責(zé)包括:實(shí)例化、定位、配置應(yīng)?程序中的 對(duì)象及建?這些對(duì)象間的依賴。
BeanFactory只是個(gè)接?,并不是IOC容器的具體實(shí)現(xiàn),但是Spring容器給出了很多種實(shí)現(xiàn),如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常?的?個(gè),該實(shí)現(xiàn)將以XML?式描述組成應(yīng)?的對(duì)象及對(duì)象間的依賴關(guān)系。XmlBeanFactory類(lèi)將持有此XML配置元數(shù)據(jù),并?它來(lái)構(gòu)建?個(gè)完全可配置的系統(tǒng)或應(yīng)?。 都是附加了某種功能的實(shí)現(xiàn)。它為其他具體的IOC容器提供了最基本的規(guī)范,例如 DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext 等具體的容器都是實(shí)現(xiàn)了 BeanFactory,再在其基礎(chǔ)之上附加了其他的功能。
BeanFactory和ApplicationContext就是spring框架的兩個(gè)IOC容器,現(xiàn)在?般使?ApplicationnContext,其不但包含了BeanFactory的作?,同時(shí)還進(jìn)?更多的擴(kuò)展。
BeanFacotry是spring中?較原始的Factory。如XMLBeanFactory就是?種典型的BeanFactory。 原始的BeanFactory?法?持spring的許多插件,如AOP功能、Web應(yīng)?等。ApplicationContext接?, 它由BeanFactory接?派??來(lái), ApplicationContext包含BeanFactory的所有功能,通常建議?BeanFactory優(yōu)先ApplicationContext以?種更向?向框架的?式?作以及對(duì)上下?進(jìn)?分層和實(shí)現(xiàn)繼承,ApplicationContext包還提供了以下的功能:
- MessageSource, 提供國(guó)際化的消息訪問(wèn)
- 資源訪問(wèn),如URL和?件
- 事件傳播
- 載?多個(gè)(有繼承關(guān)系)上下? ,使得每?個(gè)上下?都專(zhuān)注于?個(gè)特定的層次,?如應(yīng)?的web層;
BeanFactory提供的?法及其簡(jiǎn)單,僅提供了六種?法供客戶調(diào)?:
- boolean containsBean(String beanName) 判斷??中是否包含給定名稱(chēng)的bean定義,若有則返回true
- Object getBean(String) 返回給定名稱(chēng)注冊(cè)的bean實(shí)例。根據(jù)bean的配置情況,如果是 singleton模式將返回?個(gè)共享實(shí)例,否則將返回?個(gè)新建的實(shí)例,如果沒(méi)有找到指定bean,該?法可能會(huì)拋出異常
- Object getBean(String, Class) 返回以給定名稱(chēng)注冊(cè)的bean實(shí)例,并轉(zhuǎn)換為給定class類(lèi)型
- Class getType(String name) 返回給定名稱(chēng)的bean的Class,如果沒(méi)有找到指定的bean實(shí)例,則排除NoSuchBeanDefinitionException異常
- boolean isSingleton(String) 判斷給定名稱(chēng)的bean定義是否為單例模式
- String[] getAliases(String name) 返回給定bean名稱(chēng)的所有別名
?般情況下,Spring通過(guò)反射機(jī)制利? <bean><bean> 的class屬性指定實(shí)現(xiàn)類(lèi)實(shí)例化Bean,在某些情況下,實(shí)例化Bean過(guò)程?較復(fù)雜,如果按照傳統(tǒng)的?式,則需要在 <bean> <bean> 中提供?量的配置信息。配置?式的靈活性是受限的,這時(shí)采?編碼的?式可能會(huì)得到?個(gè)簡(jiǎn)單的?案。
Spring為此提供了?個(gè)org.springframework.bean.factory.FactoryBean的??類(lèi)接?,?戶可以通過(guò)實(shí)現(xiàn)該接?定制實(shí)例化Bean的邏輯。FactoryBean接?對(duì)于Spring框架來(lái)說(shuō)占?重要的地位,Spring?身就提供了70多個(gè)FactoryBean的實(shí)現(xiàn)。它們隱藏了實(shí)例化?些復(fù)雜Bean的細(xì)節(jié),給上層應(yīng)?帶來(lái)了便利。從Spring3.0開(kāi)始,F(xiàn)actoryBean開(kāi)始?持泛型,即接?聲明改為 FactoryBean<T> 的形式以Bean結(jié)尾,表示它是?個(gè)Bean,不同于普通Bean的是:它是實(shí)現(xiàn)了 FactoryBean<T> 接?的Bean,根據(jù)該Bean的ID從BeanFactory中獲取的實(shí)際上是FactoryBean的getObject()返回的對(duì)象,?不是FactoryBean本身,如果要獲取FactoryBean對(duì)象,請(qǐng)?jiān)趇d前?加?個(gè)&符號(hào)來(lái)獲取。
例如??實(shí)現(xiàn)?個(gè)FactoryBean,功能:?來(lái)代理?個(gè)對(duì)象,對(duì)該對(duì)象的所有?法做?個(gè)攔截,在調(diào)?前后都輸出??LOG,模仿ProxyFactoryBean的功能。FactoryBean是?個(gè)接?,當(dāng)在IOC容器中的Bean實(shí)現(xiàn)了FactoryBean后,通過(guò)getBean(StringBeanName)獲取到的Bean對(duì)象并不是FactoryBean的實(shí)現(xiàn)類(lèi)對(duì)象,?是這個(gè)實(shí)現(xiàn)類(lèi)中的getObject()?法返回的對(duì)象。要想獲取FactoryBean的實(shí)現(xiàn)類(lèi),就要getBean(&BeanName),在BeanName之前加上&。
總結(jié)
BeanFactory是個(gè)Factory,也就是IOC容器或?qū)ο??,F(xiàn)actoryBean是個(gè)Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)來(lái)進(jìn)?管理的。
但對(duì)FactoryBean??,這個(gè)Bean不是簡(jiǎn)單的Bean,?是?個(gè)能?產(chǎn)或者修飾對(duì)象?成的??Bean,它的實(shí)現(xiàn)與設(shè)計(jì)模式中的??模式和修飾器模式類(lèi)似

浙公網(wǎng)安備 33010602011771號(hào)