Spring相關(guān)面試題

介紹下什么是Spring?

Spring是一個輕量級Java開發(fā)框架,最早有Rod Johnson創(chuàng)建,目的是為了解決企業(yè)級應(yīng)用開發(fā)的業(yè)務(wù)邏輯層和其他各層的耦合問題。它是一個分層的JavaSE/JavaEE full-stack (一站式)輕量級開源框架,為開發(fā)Java應(yīng)用程序提供全面的基礎(chǔ)架構(gòu)支持。Spring負(fù)責(zé)基礎(chǔ)架構(gòu),因此Java開發(fā)者可以專注于應(yīng)用程序的開發(fā)。

Spring最根本的使命是解決企業(yè)級應(yīng)用開發(fā)的復(fù)雜性,即簡化Java開發(fā)。

Spring可以做很多事情,它為企業(yè)級開發(fā)提供給了豐富的功能,但是這些功能的底層都依賴于它的兩個核心特性,也就是依賴注入(dependency injection,DI) *和 *面向切面編程(aspect-oriented programming,AOP)。

為了降低Java開發(fā)的復(fù)雜性,Spring采取了以下4種關(guān)鍵策略·

基于POJO的輕量級和最小侵入性編程;

通過依賴注入和面向接口實現(xiàn)松耦合;

基于切面和慣例進行聲明式編程;

通過切面和模板減少樣板式代碼。

Spring框架都有哪些特點?

輕量級

從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個大小只有1M多的JAR文件里發(fā)布,并且Spring所需的處理開銷也是微不足道的。

此外,Spring是非侵入式的∶典型的,Spring應(yīng)用中的對象不依賴于Spring的特定類。

控制反轉(zhuǎn)

Spring通過一種稱作控制反轉(zhuǎn)IOC的技術(shù)促進了低耦合。

當(dāng)應(yīng)用了IOC,一個對象依賴的其他對象會通過被動的方式傳遞進來,而不是這個對象自己創(chuàng)建或者查找依賴對象。

面向切面

Spring支持面向切面的編程,并且把應(yīng)用業(yè)務(wù)邏輯和系統(tǒng)服務(wù)分開

容器

Spring包含并管理應(yīng)用對象的配置和生命周期,在這個意義上它是一種容器,你可以配置你的每個bean如何被創(chuàng)建(基于一個可配置原型,你的bean可以創(chuàng)建一個單獨的實例或者每次需要時都生成—個新的實例)以及它們是如何相互關(guān)聯(lián)的。

框架集合

Spring可以將簡單的組件配置、組合成為復(fù)雜的應(yīng)用。

在Spring中,應(yīng)用對象被聲明式地組合,典型的是在一個XML文件里。

Spring也提供了很多基礎(chǔ)功能(事務(wù)管理、持久化框架集成等),將應(yīng)用邏輯的開發(fā)留給開發(fā)者。

Spring由哪些模塊組成?(列舉?些重要的Spring模塊?)

Spring總共大約有20個模塊,由1300多個不同的文件構(gòu)成。而這些組件被分別整合在核心容器(Core container) 、AOP(Aspect oriented Programming)設(shè)備支持(Instrmentation).數(shù)據(jù)訪問與集成(Data Access/Integeration)web消息(Messaging)、Test等6個模塊中。以下是Spring 4的模塊結(jié)構(gòu)圖:

Spring模塊圖

常用模塊(重要模塊):

Spring Core:提供了框架的基本組成部分,包括控制反轉(zhuǎn)(Inversion of Control,IOC)和依賴注入(Dependency Injection,DI)功能。

Spring Beans:提供了BeanFactory,是工廠模式的一個經(jīng)典實現(xiàn),Spring將管理對象稱為Bean。

Spring Context:構(gòu)建于core封裝包基礎(chǔ)上的context封裝包,提供了一種框架式的對象訪問方法。

SpringJDBC:提供了一個JDBC的抽象層,消除了煩瑣的JDBC編碼和數(shù)據(jù)庫廠商特有的錯誤代碼解析,用于簡化JDBC。

Spring ROM: Spring框架插入了若千個 ORM框架,從而提供了ORM的對象關(guān)系工具,其中包括JDO、 Hibernate和Batis SQL Map。所有這些都遭從Spring 的通用事務(wù)和DAO異棠層次結(jié)構(gòu)。

SpringAOP:提供了面向切面的編程實現(xiàn),讓你可以自定義攔截器、切點等。

SpringWeb:提供了針對Web開發(fā)的集成特性,例如文件上傳,利用servlet listeners進行ioc容器初始化和針對Web的ApplicationContext。

SpringTest:主要為測試提供支持的,支持使用JUnit或TestNG對Spring組件進行單元測試和集成測試。

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

  1. 工廠模式: BeanFactory就是簡單工廠模式的體現(xiàn),用來創(chuàng)建對象的實例;

  2. 單例模式: Bean默認(rèn)為單例模式。

  3. 代理模式: Spring的AOP功能用到了JDK的動態(tài)代理和CGLIB字節(jié)碼生成技術(shù);

  4. 適配器模式: Spring AOP 的增強或通知(Advice)使?到了適配器模式、spring MVC 中也是?到了適配器模式適配 Controller 。

  5. 模板方法: 用來解決代碼重復(fù)的問題。比如.RestTemplate, JmsTemplate, JpaTemplate。

  6. 觀察者模式:定義對象鍵一種一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都會得到通知被制動更新,如Spring中l(wèi)istener的實現(xiàn)-ApplicationListener。

  7. 包裝器設(shè)計模式 : 我們的項?需要連接多個數(shù)據(jù)庫,?且不同的客戶在每次訪問中根據(jù)需要會去訪問不同的數(shù)據(jù)庫。這種模式讓我們可以根據(jù)客戶的需求能夠動態(tài)切換不同的數(shù)據(jù)源。

Spring IOC & AOP

什么是IOC容器?

IOC(Inversion of Control)即控制反轉(zhuǎn)是一種設(shè)計思想,它把傳統(tǒng)上由程序代碼直接操控的對象的調(diào)用權(quán)交給容器,通過容器來實現(xiàn)對象組件的裝配和管理。所謂的”控制反轉(zhuǎn)”概念就是對組件對象控制權(quán)的轉(zhuǎn)移,從程序代碼本身轉(zhuǎn)移到了外部容器。

Spring lOC負(fù)責(zé)創(chuàng)建對象,管理對象(通過依賴注入(DI),裝配對象,配置對象,并且管理這些對象的整個生命周期。

IoC 容器實際上就是個Map(key, value) ,Map 中存放的是各種對象。

什么是依賴注入?

依賴注入:相對于loC而言,依賴注入(DI)更加準(zhǔn)確地描述了loC的設(shè)計理念。所謂依賴注入

(Dependency Injection),即組件之間的依賴關(guān)系由容器在應(yīng)用系統(tǒng)運行期來決定,也就是由容器動態(tài)地將某種依賴關(guān)系的目標(biāo)對象實例注入到應(yīng)用系統(tǒng)中的各個關(guān)聯(lián)的組件之中。組件不做定位查詢,只提供普通的Java方法讓容器去決定依賴關(guān)系??偨Y(jié):依賴于容器的注入對象

SpringBean的作用域?

Spring應(yīng)用上下文中所有bean默認(rèn)都是作為singleton(單例),不管bean被注入多少次都是同一個實例。

Spring的Bean 定義了 5 種作用域 : 分別為 singleton(單例)、prototype(原型)、

request、session 和 global session

Singleton:單例模式(多線程下不安全)

Spring IoC 容器中只會存在一個共享的 Bean 實例,無論有多少個

Bean 引用它,始終指向同一對象。該模式在多線程下是不安全的。Singleton 作用域是Spring 中的缺省作用域,也可以顯示的將 Bean 定義為 singleton 模式,配置為:

|

<bean id="userDao" class="com.ioc.UserDaoImpl" scope="singleton"/>

|

Prototype:原型模式(每次使用時創(chuàng)建)

每次通過 Spring 容器獲取 prototype 定義的 bean 時,容器都將創(chuàng)建一個新的 Bean 實例,每個 Bean 實例都有自己的屬性和狀態(tài),而 singleton 全局只有一個對象。根據(jù)經(jīng)驗,對有狀態(tài)的 bean 使用 prototype 作用域,而對無狀態(tài)的 bean 使用 singleton作用域。

Request(一個request一個實例):

在一次 Http 請求中,容器會返回該 Bean 的同一實例。而對不同的 Http 請求則會產(chǎn)生新的 Bean,而且該 bean 僅在當(dāng)前 Http Request 內(nèi)有效,當(dāng)前 Http 請求結(jié)束,該 bean實例也將會被銷毀。

|

<bean id="loginAction" class="com.cnblogs.Login" scope="request"/>

|

Session:

在一次 Http Session 中,容器會返回該 Bean 的同一實例。而對不同的 Session 請

求則會創(chuàng)建新的實例,該 bean 實例僅在當(dāng)前 Session 內(nèi)有效。同 Http 請求相同,每一次session 請求創(chuàng)建新的實例,而不同的實例之間不共享屬性,且實例僅在自己的 session 請求內(nèi)有效,請求結(jié)束,則實例將被銷毀。

|

<bean id="userPreference" class="com.ioc.UserPreference" scope="session"/>

|

Global Session

在一個全局的 Http Session 中,容器會返回該 Bean 的同一個實例,僅在

使用 portlet context 時有效。

注意:缺省的Spring bean的作用域是Singleton。使用prototype作用域需要慎重的思考,因為頻繁創(chuàng)建和銷毀bean 會帶來很大的性能開銷。

你怎么定義Bean(類)的作用域?

當(dāng)定義一個在Spring里,我們還能給這個bean聲明一個作用域。它可以通過bean定義中的scope屬性來定義。如,當(dāng)Spring要在需要的時候每次生產(chǎn)一個新的bean實例,bean的scope屬性被指定為prototype。另一方面,一個bean每次使用的時候必須返回同一個實例,這個bean的scope屬性必須設(shè)為singleton。

Spring 中的單例 bean 的線程安全問題了解嗎?(為什么單例模式線程不安全?)

單例 bean 存在線程問題,主要是因為當(dāng)多個線程操作同?個對象的時候,對這個對象的?靜態(tài)成員變量的寫操作會存在線程安全問題。

實際上大部分時候spring bean無狀態(tài)的(比如dao類),所有某種程度上來說bean也是安全的,但如果bean 有狀態(tài)的話(比如view model對象),那就要開發(fā)者自己去保證線程安全了,最簡單的就是改變bean 的作用域,把"singleton"變更為"prototype”,這樣請求bean相當(dāng)于new Bean()了,所以就可以保證線程安全了。

·有狀態(tài)就是有數(shù)據(jù)存儲功能?!o狀態(tài)就是不會保存數(shù)據(jù)。

常見的兩種解決方式:

1. 在Bean對象中盡量避免定義可變的成員變量(不太現(xiàn)實)。

2. 在類中定義?個ThreadLocal成員變量,將需要的可變成員變量保存在 ThreadLocal 中(推薦的?種?式)。

Spring Bean 生命周期

實例化

  1. 實例化一個Bean,就是new 一個對象

IOC依賴注入

  1. 按照Spring上下文對實例化的Bean進行配置,也就是IOC注入。

setBeanName

  1. 如果 Bean 實現(xiàn)了 BeanNameAware 接?,調(diào)? setBeanName() ?法,傳?Bean的名字。

BeanFactoryAware 實現(xiàn)

  1. 如果Bean 實現(xiàn)了 BeanFactoryAware 接口,會調(diào)用它實現(xiàn)的 setBeanFactory()方法。

ApplicationContextAware 實現(xiàn)

  1. 如果Bean實現(xiàn)了ApplicationContextAware接口,會調(diào)用setApplicationContext(ApplicationContext)方法,傳入 Spring 上下文(同樣這個方式也可以實現(xiàn)步驟 4 的內(nèi)容,但比 4 更好,因為 ApplicationContext 是 BeanFactory 的子接口,有更多的實現(xiàn)方法)

postProcessBeforelnitialization接口實現(xiàn)-初始化預(yù)處理

  1. 如果Bean關(guān)聯(lián)了BeanPostProcessor接口,將會調(diào)用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor 經(jīng)常被用作是 Bean 內(nèi)容的更改,并且由于這個是在 Bean 初始化結(jié)束時調(diào)用那個的方法,也可以被應(yīng)用于內(nèi)存或緩存技術(shù)。

init-method

  1. 如果 Bean 在 Spring 配置文件中配置了 init-method 屬性會自動調(diào)用其配置的初始化方法。

postProcessAfterInitialization

  1. 如果Bean關(guān)聯(lián)了BeanPostProcessor接口,將會調(diào)用postProcessAfterInitialization(Object obj, String s)方法。

注:以上工作完成以后就可以應(yīng)用這個 Bean 了,那這個 Bean 是一個 Singleton 的,所以一般情況下我們調(diào)用同一個 id 的 Bean 會是在內(nèi)容地址相同的實例,當(dāng)然在 Spring 配置文件中也可以配置非 Singleton。

Destroy過期自動清理階段

  1. 當(dāng)要銷毀 Bean 的時候,如果 Bean 實現(xiàn)了 DisposableBean 接?,執(zhí)? destroy() ?法

destroy-method自配置清理

  1. 當(dāng)要銷毀 Bean 的時候,如果 Bean 在配置?件中的定義包含 destroy-method 屬性,執(zhí)?指定的?法。
中文解釋流程圖

BeanFactory和FactoryBean的區(qū)別?

BeanFactory:是一個工廠,IOC的頂級接口(其實是構(gòu)建了一個spring上下文的環(huán)境,容器),用來管理和獲取Bean對象。

FactoryBean:是一個Bean生成工具,是用來獲取一種類型對象的Bean,它是構(gòu)造Bean實例的一種方式。用戶可以通過實現(xiàn)該接口定制實例化Bean的邏輯。

Spring 依賴注入的方式?

4種:構(gòu)造器注入、setter方法注入、靜態(tài)工廠注入、實例工廠注入

構(gòu)造器依賴注入:構(gòu)造器依賴注入通過容器觸發(fā)一個類的構(gòu)造器來實現(xiàn)的,該類有一系列參數(shù),每個參數(shù)代表一個對其他類的依賴。

Setter方法注入: Setter方法注入是容器通過調(diào)用無參構(gòu)造器或無參static工廠方法實例化bean之后,調(diào)用該bean的setter方法,即實現(xiàn)了基于setter的依賴注入。

**靜態(tài)工廠注入: **通過調(diào)用靜態(tài)工廠的方法來獲取自己需要的對象,為了讓 spring 管理所有對象,我們不能直接通過"工程類.靜態(tài)方法()"來獲取對象,而是依然通過 spring 注入的形式獲取。

實例工廠注入: 獲取對象實例的方法不是靜態(tài)的,所以你需要首先 new 工廠類,再調(diào)用普通的實例方法。

最常用的是構(gòu)造器和setter方式的注入。

兩者區(qū)別:

兩者區(qū)別對比圖

兩種依賴方式都可以使用,構(gòu)造器注入和Setter方法注入。最好的解決方案是用構(gòu)造器參數(shù)實現(xiàn)強制依賴,setter方法實現(xiàn)可選依賴。

什么是Bean的裝配?

裝配,或bean裝配是指在Spring容器中把bean組裝到一起,前提是容器需要知道bean的依賴關(guān)系,如何通過依賴注入來把它們裝配到一起。

什么是bean的自動裝配?

在Spring框架中,在配置文件中設(shè)定bean的依賴關(guān)系是一個很好的機制,Spring容器能夠自動裝配相互合作的bean,這意味著容器不需要和配置,能通過Bean工廠自動處理bean之間的協(xié)作。這意味著Spring可以通過向Bean Factory中注入的方式自動搞定bean之間的依賴關(guān)系。自動裝配可以設(shè)置在每個bean上,也可以設(shè)定在特定的bean上。

解釋不同方式的自動裝配,spring自動裝配bean有哪些方式?

在spring中,對象無需自己查找或創(chuàng)建與其關(guān)聯(lián)的其他對象,由容器負(fù)責(zé)把需要相互協(xié)作的對象引用賦予各個對象,使用autowire來配置自動裝載模式。

在Spring框架xml配置中共有5種自動裝配:

no: 默認(rèn)的方式是不進行自動裝配的,通過手工設(shè)置ref屬性來進行裝配bean。

byName:通過bean的名稱進行自動裝配,如果一個bean的property與另一bean的name相同,就進行自動裝配。

byType:通過參數(shù)的數(shù)據(jù)類型進行自動裝配。

constructor:利用構(gòu)造函數(shù)進行裝配,并且構(gòu)造函數(shù)的參數(shù)通過byType進行裝配。

autodetect:自動探測,如果有構(gòu)造方法,通過construct的方式自動裝配,否則使用byType的方式自動裝配。

使用@Autowired注解自動裝配的過程是怎樣的?

使用@Autowired注解來自動裝配指定的bean。

在使用@Autowired注解之前需要在Spring配置文件進行配置,<context:annotation-config />。

在啟動spring loC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor后置處理器,當(dāng)容器掃描到@Autowied、@Resource或@Inject時,就會在IOC容器自動查找需要的bean,并裝配給該對象的屬性。在使用@Autowired時,首先在容器中查詢對應(yīng)類型的bean:

如果查詢結(jié)果剛好為一個,就將該bean裝配給@Autowired指定的數(shù)據(jù);·

如果查詢的結(jié)果不止一個,那么@Autowired會根據(jù)名稱來查找;

如果上述查找的結(jié)果為空,那么會拋出異常。解決方法時,使用required=false。

將?個類聲明為Spring的 bean 的注解有哪些?

@Component :通?的注解,可標(biāo)注任意類為 Spring 組件。如果?個Bean不知道屬于哪個層,可以使? @Component 注解標(biāo)注。

@Repository : 對應(yīng)持久層即 Dao 層,主要?于數(shù)據(jù)庫相關(guān)操作。

@Service : 對應(yīng)服務(wù)層,主要涉及?些復(fù)雜的邏輯,需要?到 Dao層。

@Controller : 對應(yīng) Spring MVC 控制層,主要?戶接受?戶請求并調(diào)? Service 層返回數(shù)

據(jù)給前端??。

@Component 和 @Bean 的區(qū)別是什么?

  1. 作?對象不同: @Component 注解作?于類,? @Bean 注解作?于?法。

  2. @Component 通常是通過類路徑掃描來?動偵測以及?動裝配到Spring容器中(我們可以使? @ComponentScan 注解定義要掃描的路徑從中找出標(biāo)識了需要裝配的類?動裝配到Spring 的 bean 容器中)。

@Bean 注解通常是我們在標(biāo)有該注解的?法中定義產(chǎn)?這個bean, @Bean 告訴了Spring這是某個類的示例,當(dāng)我需要?它的時候還給我。

  1. @Bean 注解? Component 注解的?定義性更強,?且很多地?我們只能通過 @Bean 注解來注冊bean。?如當(dāng)我們引?第三?庫中的類需要裝配到 Spring 容器時,則只能通過

@Bean 來實現(xiàn)。

@component, @Controller,@Repository,@Service有何區(qū)別?

@Component:這將java類標(biāo)記為bean。它是任何Spring管理組件的通用構(gòu)造型。spring的組件掃描機制現(xiàn)在可以將其拾取并將其拉入應(yīng)用程序環(huán)境中。

@Controller:這將一個類標(biāo)記為Spring Web MVC控制器。標(biāo)有它的Bean 會自動導(dǎo)入到IOC容器中。

@Service:此注解是組件注解的特化。它不會對@Component注解提供任何其他行為。您可以在服務(wù)層類中使用@Service而不是@Component,因為它以更好的方式指定了意圖。

@Repository:這個注解是具有類似用途和功能的@Component注解的特化。它為DAO提供了額外的好處。它將DAO導(dǎo)入IOC容器,并使未經(jīng)檢查的異常有資格轉(zhuǎn)換為Spring DataAccessException。

@Autowired注解有什么作用

@Autowired默認(rèn)是按照類型裝配注入的,默認(rèn)情況下它要求依賴對象必須存在(可以設(shè)置它required屬性為false)。@Autowired 注解提供了更細粒度的控制,包括在何處以及如何完成自動裝配。它的用法和@Required一樣,修飾setter方法、構(gòu)造器、屬性或者具有任意名稱和/或多個參數(shù)的PN方法。

@Autowired和@Resource之間的區(qū)別

@Autowired可用于: 構(gòu)造函數(shù)、成員變量、Setter方法

@Autowired和@Resource之間的區(qū)別

相同點:

1,@Autowired和@Resource功能相同,都可以用來裝配bean;

2,兩個注解可以加載屬性字段或?qū)懺趕etter方法上;

不同點:

1,提供方不同:@Autowired是Spring框架提供,@Resource是Java自帶,jdk1.6版本開始支持;

2,裝配方式不同:

@Autowired默認(rèn)按照byType裝配;

@Resource默認(rèn)按照byName裝配,如果匹配不到,則繼續(xù)使用byType裝配;

@Qualifier注解有什么作用

當(dāng)您創(chuàng)建多個相同類型的bean并希望僅使用屬性裝配其中一個bean時,您可以使用@Qualifier注解和@Autowired通過指定應(yīng)該裝配哪個確切的bean來消除歧義。

@RequestMapping 注解有什么用?

@RequestMapping注解用于將特定HTTP請求方法映射到將處理相應(yīng)請求的控制器中的特定類/方法。此注釋可應(yīng)用于兩個級別:

類級別:注解寫在類上,映射請求的URL

方法級別:注解寫在對應(yīng)的方法上,映射URL以及HTTP請求方法

@RestController vs @Controller

Controller 返回?個??

單獨使? @Controller 不加 @ResponseBody 的話?般使?在要返回?個視圖的情況,這種情況屬于??傳統(tǒng)的Spring MVC 的應(yīng)?,對應(yīng)于前后端不分離的情況。

@RestController 返回JSON 或 XML 形式數(shù)據(jù)

但 @RestController 只返回對象,對象數(shù)據(jù)直接以 JSON 或 XML 形式寫? HTTP 響應(yīng)(Response)中,這種情況屬于 RESTful Web服務(wù),這也是?前?常開發(fā)所接觸的最常?的情況(前后端分離)。

@Controller +@ResponseBody 返回JSON 或 XML 形式數(shù)據(jù)

如果你需要在Spring4之前開發(fā) RESTful Web服務(wù)的話,你需要使? @Controller 并結(jié)合 @ResponseBody 注解,也就是說 @Controller + @ResponseBody = @RestController (Spring 4之后新加的注解)。

注意部分

解釋下什么是AOP?你的理解是什么?

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

Spring AOP就是基于動態(tài)代理的,如果要代理的對象,實現(xiàn)了某個接?,那么Spring AOP會使?JDK Proxy,去創(chuàng)建代理對象,?對于沒有實現(xiàn)接?的對象,就?法使? JDK Proxy 去進?代理了,這時候Spring AOP會使?Cglib ,這時候Spring AOP會使? Cglib ?成?個被代理對象的?類來作為代理,使? AOP 之后我們可以把?些通?功能抽象出來,在需要?到的地?直接使?即可,這樣??簡化了代碼量。我們需要增加新功能時也?便,這樣也提?了系統(tǒng)擴展性。?志功能、事務(wù)管理等等場景都?到了 AOP 。

JDK動態(tài)代理和CGLIB動態(tài)代理的區(qū)別

Spring AOP中的動態(tài)代理主要有兩種方式,JDK動態(tài)代理和CGLIB動態(tài)代理:

JDK動態(tài)代理只提供接口的代理,不支持類的代理。核心InvocationHandler接口和Proxy類,lnvocationHandler通過invoke()方法反射來調(diào)用目標(biāo)類中的代碼,動態(tài)地將橫切邏輯和業(yè)務(wù)編織在一起;接著,Proxy利用InvocationHandler動態(tài)創(chuàng)建一個符合某一接口的的實例,生成目標(biāo)類的代理對象。

如果代理類沒有實現(xiàn)InvocationHandler接口,那么Spring AOP會選擇使用CGLIB來動態(tài)代理目標(biāo)類。CGLIB (Code Generation Library),是一個代碼生成的類庫,可以在運行時動態(tài)的生成指定類的一個子類對象,并覆蓋其中特定方法并添加增強代碼,從而實現(xiàn)AOP。CGLIB是通過繼承的方式做的動態(tài)代理,因此如果某個類被標(biāo)記為final,那么它是無法使用CGLIB做動態(tài)代理的。

靜態(tài)代理與動態(tài)代理區(qū)別在于生成AOP代理對象的時機不同,相對來說AspectJ的靜態(tài)代理方式具有更好的性能,但是AspectJ需要特定的編譯器進行處理,而Spring AOP則無需特定的編譯器處理。

說明圖片

解釋下SpringAOP里面的幾個名詞

切面(Aspect)

切面是通知和切點的結(jié)合。通知和切點共同定義了切面的全部內(nèi)容。在SpringAOP中,切面可以使用通用類(基于模式的風(fēng)格)或者在普通類中以@AspectJ注解來實現(xiàn)。

連接點(Join point)

指方法,在Spring AOP中,一個連接點總是代表一個方法的執(zhí)行。應(yīng)用可能有數(shù)以千計的時機應(yīng)用通知。這些時機被稱為連接點。連接點是在應(yīng)用執(zhí)行過程中能夠插入切面的一個點。這個點可以是調(diào)用方法時、拋出異常時、甚至修改一個字段時。切面代碼可以利用這些點插入到應(yīng)用的正常流程之中,并添加新的行為。

通知(Advice)

在AOP術(shù)語中,切面的工作被稱為通知。

切入點(Pointcut)

切點的定義會匹配通知所要織入的一個或多個連接點。我們通常使用明確的類和方法名稱,或是利用正則表達式定義所匹配的類和方法名稱來指定這些切點。

引入(lntroduction)

引入允許我們向現(xiàn)有類添加新方法或?qū)傩浴?/p>

目標(biāo)對象(Target Object)

被一個或者多個切面(aspect)所通知(advise)的對象。它通常是一個代理對象。也有人把它叫做被通知(adviced)對象。既然Spring AOP是通過運行時代理實現(xiàn)的,這個對象永遠是一個被代理(proxied)對象。

織入(Weaving)

織入是把切面應(yīng)用到目標(biāo)對象并創(chuàng)建新的代理對象的過程。在目標(biāo)對象的生命周期里有多少個點可以進行織入:

編譯期:切面在目標(biāo)類編譯時被織入。AspectJ的織入編譯器是以這種方式織入切面的。

類加載期:切面在目標(biāo)類加載到VM時被織入。需要特殊的類加載器,它可以在目標(biāo)類被引入應(yīng)用之前增強該目標(biāo)類的字節(jié)碼。AspectJ5的加載時織入就支持以這種方式織入切面。

運行期:切面在應(yīng)用運行的某個時刻被織入。一般情況下,在織入切面時,AOP容器會為目標(biāo)對象動態(tài)地創(chuàng)建一個代理對象。SpringAOP就是以這種方式織入切面。

spring通知有哪些類型?

在AOP術(shù)語中,切面的工作被稱為通知,實際上是程序執(zhí)行時要通過SpringAOP框架觸發(fā)的代碼段。Spring切面可以應(yīng)用5種類型的通知:

  1. 前置通知(Before) : 在目標(biāo)方法被調(diào)用之前調(diào)用通知功能;

  2. 后置通知(After)∶在目標(biāo)方法完成之后調(diào)用通知,此時不會關(guān)心方法的輸出是什么;

  3. 返回通知(After-returning ) : 在目標(biāo)方法成功執(zhí)行之后調(diào)用通知;

  4. 異常通知(After-throwing): 在目標(biāo)方法拋出異常后調(diào)用通知;

  5. 環(huán)繞通知(Around): 通知包裹了被通知的方法,在被通知的方法調(diào)用之前和調(diào)用之后執(zhí)行自定義的行為。

通知類型執(zhí)行順序

什么是切面Aspect?

aspect由pointcount和advice組成,切面是通知和切點的結(jié)合。

它既包含了橫切邏輯的定義,也包括了連接點的定義.

Spring AOP就是負(fù)責(zé)實施切面的框架,它將切面所定義的橫切邏輯編織到切面所指定的連接點中.

AOP的工作重心在于如何將增強編織目標(biāo)對象的連接點上,這里包含兩個工作:

如何通過pointcut和advice定位到特定的joinpoint 上

如何在advice中編寫切面代碼.

可以簡單地認(rèn)為,使用@Aspect注解的類就是切面.

切面示意圖

Spring支持的事務(wù)管理類型,spring事務(wù)實現(xiàn)方式有哪些?

Spring支持兩種類型的事務(wù)管理:

編程式事務(wù)管理:通過編程的方式管理事務(wù),給你帶來極大的靈活性,但是難維護。

編程式事務(wù)管理通過TransactionTemplate手動管理事務(wù),硬編碼方式(不推薦使用)

聲明式事務(wù)管理:你可以將業(yè)務(wù)代碼和事務(wù)管理分離,你只需用注解和XML配置來管理事務(wù)。(在配置文件中配置,推薦使用)

聲明式事務(wù)管理有三種實現(xiàn)方式:

基于TransactionProxyFactoryBean的方式。

基于AspectJ的XML方式。

基于注解的方式大部分。service類名上或方法上添加@Transactional 注解

你更傾向用那種事務(wù)管理類型?

我會選擇聲明式事務(wù)管理,因為它對應(yīng)用代碼的影響最小,因此更符合一個無侵入的輕量級容器的思想。聲明式事務(wù)管理要優(yōu)于編程式事務(wù)管理,雖然比編程式事務(wù)管理(這種方式允許你通過代碼控制事務(wù))少了一點靈活性。唯一不足地方是,最細粒度只能作用到方法級別,無法做到像編程式事務(wù)那樣可以作用到代碼塊級別。

Spring事務(wù)的實現(xiàn)方式和實現(xiàn)原理

Spring事務(wù)的本質(zhì)其實就是數(shù)據(jù)庫對事務(wù)的支持,沒有數(shù)據(jù)庫的事務(wù)支持,spring是無法提供事務(wù)功能的。真正的數(shù)據(jù)庫層的事務(wù)提交和回滾是通過binlog或者redo log實現(xiàn)的。

說一下Spring的事務(wù)傳播行為

spring事務(wù)的傳播行為說的是,當(dāng)多個事務(wù)同時存在的時候,spring如何處理這些事務(wù)的行為。一共七種傳播行為:

PROPAGATION_REQUIRED(required):如果當(dāng)前沒有事務(wù),就創(chuàng)建一個新事務(wù),如果當(dāng)前存在事務(wù),就加入該事務(wù),該設(shè)置是最常用的設(shè)置。

PROPAGATION_SUPPORTS(supports): 支持當(dāng)前事務(wù),如果當(dāng)前存在事務(wù),就加入該事務(wù),如果當(dāng)前不存在事務(wù),就以非事務(wù)執(zhí)行。

PROPAGATION_MANDATORY(mandatory):支持當(dāng)前事務(wù),如果當(dāng)前存在事務(wù),就加入該事務(wù),如果當(dāng)前不存在事務(wù),就拋出異常。

PROPAGATION_REQUIRES_NEW(required_new):創(chuàng)建新事務(wù),無論當(dāng)前存不存在事務(wù),都創(chuàng)建新事務(wù)。

PROPAGATION_NOT_SUPPORTED(not_supported): 以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。

PROPAGATION_NEVER(never):以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。

PROPAGATION_NESTED(nested): 如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則按REQUIRED屬性執(zhí)行。

說一下Spring的事務(wù)隔離級別?

spring有五大隔離級別,默認(rèn)值為ISOLATION_DEFAULT(使用數(shù)據(jù)庫的設(shè)置),其他四個隔離級別和數(shù)據(jù)庫的隔離級別一致:

  1. lSOLATION_DEFAULT(default): 用底層數(shù)據(jù)庫的設(shè)置隔離級別,數(shù)據(jù)庫設(shè)置的是什么我就用什么;

  2. ISOLATION_READ_UNCOMMITTED(read_uncommitted): 未提交讀,最低隔離級別、事務(wù)未提交前,就可被其他事務(wù)讀?。〞霈F(xiàn)幻讀、臟讀、不可重復(fù)讀);

  3. ISOLATION_READ_COMMITTED(read_committed): 提交讀,一個事務(wù)提交后才能被其他事務(wù)讀取到(會造成幻讀、不可重復(fù)讀),SQL server的默認(rèn)級別;

  4. ISOLATION_REPEATABLE_READ(repeatable_read): 可重復(fù)讀,保證多次讀取同一個數(shù)據(jù)時,其值都和事務(wù)開始時候的內(nèi)容是一致,禁止讀取到別的事務(wù)未提交的數(shù)據(jù)(會造成幻讀),MySQL的默認(rèn)級別;

  5. ISOLATION_SERIALIZABLE(serializable):序列化,代價最高最可靠的隔離級別,該隔離級別能防止臟讀、不可重復(fù)讀、幻讀。

什么是臟讀、幻讀、不可重復(fù)讀?

臟讀∶表示一個事務(wù)能夠讀取另一個事務(wù)中還未提交的數(shù)據(jù)。比如,某個事務(wù)嘗試插入記錄A,此時該事務(wù)還未提交,然后另一個事務(wù)嘗試讀取到了記錄A。

不可重復(fù)讀︰是指在一個事務(wù)內(nèi),多次讀同一數(shù)據(jù)。

幻讀:指同一個事務(wù)內(nèi)多次查詢返回的結(jié)果集不一樣。比如同一個事務(wù)A第一次查詢時候有n條記錄,但是第二次同等條件下查詢卻有n+1條記錄,這就好像產(chǎn)生了幻覺。發(fā)生幻讀的原因也是另外一個事務(wù)新增或者刪除或者修改了第一個事務(wù)結(jié)果集里面的數(shù)據(jù),同一個記錄的數(shù)據(jù)內(nèi)容被修改了,所有數(shù)據(jù)行的記錄就變多或者變少了。

@Transactional(rollbackFor = Exception.class)注解了解嗎?

Exception分為運?時異常RuntimeException和?運?時異常。事務(wù)管理對于企業(yè)應(yīng)

?來說是?關(guān)重要的,即使出現(xiàn)異常情況,它也可以保證數(shù)據(jù)的?致性。

當(dāng) @Transactional 注解作?于類上時,該類的所有 public ?法將都具有該類型的事務(wù)屬性,同時,我們也可以在?法級別使?該標(biāo)注來覆蓋類級別的定義。如果類或者?法加了這個注解,那么這個類??的?法拋出異常,就會回滾,數(shù)據(jù)庫??的數(shù)據(jù)也會回滾。

在 @Transactional 注解中如果不配置 rollbackFor 屬性,那么事物只會在遇到 RuntimeException 的時候才會回滾,加上 rollbackFor=Exception.class ,可以讓事物在遇到?運?時異常時也回滾。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容