天天看點

這12道Spring面試題要是還不會的話?就白幹了!前言如何實作一個IOC容器Spring是什麼?談談你對AOP的了解談談你對IOC的了解描述一下Spring Bean的生命周期?解釋下Spring支援的幾種bean的作用域。Spring架構中的單例Bean是線程安全的麼?Spring 架構中都用到了哪些設計模式?Spring事務的實作方式和原理以及隔離級别?Spring事務傳播機制Spring事務什麼時候會失效?什麼是bean的自動裝配,有哪些方式?

很多朋友問,如何短時間突擊 Java 通過面試?

面試前還是很有必要針對性的刷一些題,很多朋友的實戰能力很強,但是理論比較薄弱,面試前不做準備是很吃虧的。這裡整理了很多面試常考的一些面試題,希望能幫助到你面試前的複習并且找到一個好的工作,也節省你在網上搜尋資料的時間來學習。

整理的這些Java面試題,包括Java基礎、Java多線程與并發程式設計、spring、spring mvc、spring boot、mybatis。MySQL、Redis、消息中間件MQ、分布式與微服務。持續更新中…

完整版Java面試題位址:105道Java面試題總結|含答案解析

内容

位址

Java基礎

https://blog.51cto.com/u_14442094/2690299

多線程與并發

https://blog.51cto.com/u_14442094/2696509

Spring

本文

Spring MVC、Spring Boot

未更新

MyBatis

MySQL

Redis

分布式與微服務

MQ

1、配置檔案配置包掃描路徑

2、遞歸包掃描擷取.class檔案

3、反射、确定需要交給IOC管理的類

4、對需要注入的類進行依賴注入

(1)配置檔案中指定需要掃描的包路徑

(2)定義一些注解,分别表示通路控制層、業務服務層、資料持久層、依賴注入注解、擷取配置檔案注解

(3)從配置檔案中擷取需要掃描的包路徑,擷取到目前路徑下的檔案資訊及檔案夾資訊,我們将目前路徑下所有以.class結尾的檔案添加到一個Set集合中進行存儲

(4)周遊這個set集合,擷取在類上有指定注解的類,并将其交給IOC容器,定義一個安全的Map用來存儲這些對象

(5)周遊這個IOC容器,擷取到每一個類的執行個體,判斷裡面是有有依賴其他的類的執行個體,然後進行遞歸注入

輕量級的開源的J2EE架構。它是一個容器架構,用來裝javabean(java對象),中間層架構(萬能膠)可以起一個連接配接作用,比如說把Struts和hibernate粘合在一起運用,可以讓我們的企業開發更快、更簡潔

Spring是一個輕量級的控制反轉(IoC)和面向切面(AOP)的容器架構

(1)從大小與開銷兩方面而言Spring都是輕量級的。

(2)通過控制反轉(IoC)的技術達到松耦合的目的

(3)提供了面向切面程式設計的豐富支援,允許通過分離應用的業務邏輯與系統級服務進行内聚性的開發

(4)包含并管理應用對象(Bean)的配置和生命周期,這個意義上是一個容器。

(5)将簡單的元件配置、組合成為複雜的應用,這個意義上是一個架構。

系統是由許多不同的元件所組成的,每一個元件各負責一塊特定功能。除了實作自身核心功能之外,這些元件還經常承擔着額外的職責。例如日志、事務管理和安全這樣的核心服務經常融入到自身具有核心業務邏輯的元件中去。這些系統服務經常被稱為橫切關注點,因為它們會跨越系統的多個元件。

當我們需要為分散的對象引入公共行為的時候,OOP則顯得無能為力。也就是說,OOP允許你定義從上到下的關系,但并不适合定義從左到右的關系。例如日志功能。

日志代碼往往水準地散布在所有對象層次中,而與它所散布到的對象的核心功能毫無關系。

在OOP設計中,它導緻了大量代碼的重複,而不利于各個子產品的重用。

AOP:将程式中的交叉業務邏輯(比如安全,日志,事務等),封裝成一個切面,然後注入到目标對象(具體業務邏輯)中去。AOP可以對某個對象或某些對象的功能進行增強,比如對象中的方法進行增強,可以在執行某個方法之前額外的做一些事情,在某個方法執行之後額外的做一些事情。

容器概念、控制反轉、依賴注入

實際上就是個map(key,value),裡面存的是各種對象(在xml裡配置的bean節點、@repository、@service、@controller、@component),在項目啟動的時候會讀取配置檔案裡面的bean節點,根據全限定類名使用反射建立對象放到map裡、掃描到打上上述注解的類還是通過反射建立對象放到map裡。

這個時候map裡就有各種對象了,接下來我們在代碼裡需要用到裡面的對象時,再通過DI注入(autowired、resource等注解,xml裡bean節點内的ref屬性,項目啟動的時候會讀取xml節點ref屬性根據id注入,也會掃描這些注解,根據類型或id注入;id就是對象名)。

沒有引入IOC容器之前,對象A依賴于對象B,那麼對象A在初始化或者運作到某一點的時候,自己必須主動去建立對象B或者使用已經建立的對象B。無論是建立還是使用對象B,控制權都在自己手上。

引入IOC容器之後,對象A與對象B之間失去了直接聯系,當對象A運作到需要對象B的時候,IOC容器會主動建立一個對象B注入到對象A需要的地方。

通過前後的對比,不難看出來:對象A獲得依賴對象B的過程,由主動行為變為了被動行為,控制權颠倒過來了,這就是“控制反轉”這個名稱的由來。

全部對象的控制權全部上繳給“第三方”IOC容器,是以,IOC容器成了整個系統的關鍵核心,它起到了一種類似“粘合劑”的作用,把系統中的所有對象粘合在一起發揮作用,如果沒有這個“粘合劑”,對象與對象之間會彼此失去聯系,這就是有人把IOC容器比喻成“粘合劑”的由來。

“獲得依賴對象的過程被反轉了”。控制被反轉之後,獲得依賴對象的過程由自身管理變為了由IOC容器主動注入。依賴注入是實作IOC的方法,就是由IOC容器在運作期間,動态地将某種依賴關系注入到對象之中。

ApplicationContext是BeanFactory的子接口

ApplicationContext提供了更完整的功能:

①繼承MessageSource,是以支援國際化。

②統一的資源檔案通路方式。

③提供在監聽器中注冊bean的事件。

④同時加載多個配置檔案。

⑤載入多個(有繼承關系)上下文 ,使得每一個上下文都專注于一個特定的層次,比如應用的web層。

BeanFactroy采用的是延遲加載形式來注入Bean的,即隻有在使用到某個Bean時(調用getBean()),才對該Bean進行加載執行個體化。這樣,我們就不能發現一些存在的Spring的配置問題。如果Bean的某一個屬性沒有注入,BeanFacotry加載後,直至第一次使用調用getBean方法才會抛出異常。

ApplicationContext,它是在容器啟動時,一次性建立了所有的Bean。這樣,在容器啟動時,我們就可以發現Spring中存在的配置錯誤,這樣有利于檢查所依賴屬性是否注入。

ApplicationContext啟動後預載入所有的單執行個體Bean,通過預載入單執行個體bean ,確定當你需要的時候,你就不用等待,因為它們已經建立好了。

相對于基本的BeanFactory,ApplicationContext 唯一的不足是占用記憶體空間。當應用程式配置Bean較多時,程式啟動較慢。

BeanFactory通常以程式設計的方式被建立,ApplicationContext還能以聲明的方式建立,如使用ContextLoader。

BeanFactory和ApplicationContext都支援BeanPostProcessor、BeanFactoryPostProcessor的使用,但兩者之間的差別是:BeanFactory需要手動注冊,而ApplicationContext則是自動注冊。

1、解析類得到BeanDefinition

2、如果有多個構造方法,則要推斷構造方法

3、确定好構造方法後,進行執行個體化得到一個對象

4、對對象中的加了@Autowired注解的屬性進行屬性填充

5、回調Aware方法,比如BeanNameAware,BeanFactoryAware

6、調用BeanPostProcessor的初始化前的方法

7、調用初始化方法

8、調用BeanPostProcessor的初始化後的方法,在這裡會進行AOP

9、如果目前建立的bean是單例的則會把bean放入單例池

10、使用bean

11、Spring容器關閉時調用DisposableBean中destory()方法

預設,每個容器中隻有一個bean的執行個體,單例的模式由BeanFactory自身來維護。該對象的生命周期是與Spring IOC容器一緻的(但在第一次被注入時才會建立)。

為每一個bean請求提供一個執行個體。在每次注入時都會建立一個新的對象

bean被定義為在每個HTTP請求中建立一個單例對象,也就是說在單個請求中都會複用這一個單例對象。

與request範圍類似,確定每個session中有一個bean的執行個體,在session過期後,bean會随之失效。

bean被定義為在ServletContext的生命周期中複用一個單例對象。

bean被定義為在websocket的生命周期中複用一個單例對象。

全局作用域,global-session和Portlet應用相關。當你的應用部署在Portlet容器中工作時,它包含很多portlet。如果你想要聲明讓所有的portlet共用全局的存儲變量的話,那麼這全局變量需要存儲在global-session中。全局作用域與Servlet中的session作用域效果相同。

Spring中的Bean預設是單例模式的,架構并沒有對bean進行多線程的封裝處理。

如果Bean是有狀态的 那就需要開發人員自己來進行線程安全的保證,最簡單的辦法就是改變bean的作用域 把 "singleton"改為’‘protopyte’ 這樣每次請求Bean就相當于是 new Bean() 這樣就可以保證線程的安全了

(1)有狀态就是有資料存儲功能

(2)無狀态就是不會儲存資料 controller、service和dao層本身并不是線程安全的,隻是如果隻是調用裡面的方法,而且多線程調用一個執行個體的方法,會在記憶體中複制變量,這是自己的線程的工作記憶體,是安全的。

Dao會操作資料庫Connection,Connection是帶有狀态的,比如說資料庫事務,Spring的事務管理器使用Threadlocal為不同線程維護了一套獨立的connection副本,保證線程之間不會互相影響(Spring是如何保證事務擷取同一個Connection的)

不要在bean中聲明任何有狀态的執行個體變量或類變量,如果必須如此,那麼就使用ThreadLocal把變量變為線程私有的,如果bean的執行個體變量或類變量需要在多個線程之間共享,那麼就隻能使用synchronized、lock、CAS等這些實作線程同步的方法了。

由一個工廠類根據傳入的參數,動态決定應該建立哪一個産品類。

Spring中的BeanFactory就是簡單工廠模式的展現,根據傳入一個唯一的辨別來獲得Bean對象,但是否是在傳入參數後建立還是傳入參數前建立這個要根據具體情況來定。

實作了FactoryBean接口的bean是一類叫做factory的bean。其特點是,spring會在使用getBean()調 用獲得該bean時,會自動調用該bean的getObject()方法,是以傳回的不是factory這個bean,而是這個bean.getOjbect()方法的傳回值。

保證一個類僅有一個執行個體,并提供一個通路它的全局通路點

spring對單例的實作: spring中的單例模式完成了後半句話,即提供了全局的通路點BeanFactory。但沒有從構造器級别去控制單例,這是因為spring管理的是任意的java對象。

Spring定義了一個适配接口,使得每一種Controller有一種對應的擴充卡實作類,讓擴充卡代替 controller執行相應的方法。這樣在擴充Controller時,隻需要增加一個擴充卡類就完成了SpringMVC 的擴充了。

##裝飾器模式

動态地給一個對象添加一些額外的職責。就增加功能來說,Decorator模式相比生成子類更為靈活。

Spring中用到的包裝器模式在類名上有兩種表現:一種是類名中含有Wrapper,另一種是類名中含有Decorator。

切面在應用運作的時刻被織入。一般情況下,在織入切面時,AOP容器會為目标對象建立動态的建立一個代理對象。SpringAOP就是以這種方式織入切面的。 織入:把切面應用到目标對象并建立新的代理對象過程。

spring的事件驅動模型使用的是 觀察者模式 ,Spring中Observer模式常用的地方是listener的實作。

Spring架構的資源通路Resource接口。該接口提供了更強的資源通路能力,Spring 架構本身大量使用了 Resource 接口來通路底層資源。

父類定義了骨架(調用哪些方法及順序),某些特定方法由子類實作。

代碼複用,減少重複代碼。除了子類要實作的特定方法,其他方法及方法調用順序都在父類中預先寫好了。

refresh方法

在使用Spring架構時,可以有兩種使用事務的方式,一種是程式設計式的,一種是申明式的,@Transactional注解就是申明式的。

首先,事務這個概念是資料庫層面的,Spring隻是基于資料庫中的事務進行了擴充,以及提供了一些能讓程式員更加友善操作事務的方式。

比如我們可以通過在某個方法上增加@Transactional注解,就可以開啟事務,這個方法中所有的sql都會在一個事務中執行,統一成功或失敗。

在一個方法上加了@Transactional注解後,Spring會基于這個類生成一個代理對象,會将這個代理對象作為bean,當在使用這個代理對象的方法時,如果這個方法上存在@Transactional注解,那麼代理邏輯會先把事務的自動送出設定為false,然後再去執行原本的業務邏輯方法,如果執行業務邏輯方法沒有出現異常,那麼代理邏輯中就會将事務進行送出,如果執行業務邏輯方法出現了異常,那麼則會将事務進行復原。

當然,針對哪些異常復原事務是可以配置的,可以利用@Transactional注解中的rollbackFor屬性進行配置,預設情況下會對RuntimeException和Error進行復原。

spring事務隔離級别就是資料庫的隔離級别:外加一個預設級别

(1)read uncommitted(未送出讀)

(2)read committed(送出讀、不可重複讀)

(3)repeatable read(可重複讀)

(4)serializable(可串行化)

資料庫的配置隔離級别是Read Commited,而Spring配置的隔離級别是Repeatable Read,請問這時隔離級别是以哪一個為準? 以Spring配置的為準,如果spring設定的隔離級别資料庫不支援,效果取決于資料庫。

多個事務方法互相調用時,事務如何在這些方法間傳播

方法A是一個事務的方法,方法A執行過程中調用了方法B,那麼方法B有無事務以及方法B對事務的要求不同都 會對方法A的事務具體執行造成影響,同時方法A的事務對方法B的事務執行也有影響,這種影響具體是什麼就 由兩個方法所定義的事務傳播類型所決定。

REQUIRED(Spring預設的事務傳播類型):如果目前沒有事務,則自己建立一個事務,如果目前存在事務,則加入這個事務

SUPPORTS:目前存在事務,則加入目前事務,如果目前沒有事務,就以非事務方法執行

MANDATORY:目前存在事務,則加入目前事務,如果目前事務不存在,則抛出異常。

REQUIRES_NEW:建立一個新事務,如果存在目前事務,則挂起該事務。

NOT_SUPPORTED:以非事務方式執行,如果目前存在事務,則挂起目前事務

NEVER:不使用事務,如果目前事務存在,則抛出異常

NESTED:如果目前事務存在,則在嵌套事務中執行,否則REQUIRED的操作一樣(開啟一個事務)

和REQUIRES_NEW的差別

REQUIRES_NEW是建立一個事務并且新開啟的這個事務與原有事務無關,而NESTED則是目前存在事務時(我們把目前事務稱之為父事務)會開啟一個嵌套事務(稱之為一個子事務)。 在NESTED情況下父事務復原時, 子事務也會復原,而在REQUIRES_NEW情況下,原有事務復原,不會影響新開啟的事務。

和REQUIRED的差別

REQUIRED情況下,調用方存在事務時,則被調用方和調用方使用同一事務,那麼被調用方出現異常時,由于共用一個事務,是以無論調用方是否catch其異常,事務都會復原 而在NESTED情況下,被調用方發生異常 時,調用方可以catch其異常,這樣隻有子事務復原,父事務不受影響。

spring事務的原理是AOP,進行了切面增強,那麼失效的根本原因是這個AOP不起作用了!常見情況有如下幾種

1、發生自調用,類裡面使用this調用本類的方法(this通常省略),此時這個this對象不是代理類,而是UserService對象本身!

解決方法很簡單,讓那個this變成UserService的代理類即可!

2、方法不是public的

@Transactional 隻能用于 public 的方法上,否則事務不會失效,如果要用在非 public 方法上,可以開啟AspectJ 代理模式。

3、資料庫不支援事務

4、沒有被spring管理

5、異常被吃掉,事務不會復原(或者抛出的異常沒有被定義,預設為RuntimeException)

開啟自動裝配,隻需要在xml配置檔案中定義“autowire”屬性。

autowire屬性有五種裝配的方式:

(1)no – 預設情況下,自動配置是通過“ref”屬性手動設定 。

(2)byName-根據bean的屬性名稱進行自動裝配。

(3)byType-根據bean的類型進行自動裝配。

(4)constructor-類似byType,不過是應用于構造器的參數。如果一個bean與構造器參數的類型形

同,則進行自動裝配,否則導緻異常。

(5)autodetect-如果有預設的構造器,則通過constructor方式進行自動裝配,否則使用byType方式

進行自動裝配。

@Autowired自動裝配bean,可以在字段、setter方法、構造函數上使用。

上一篇: Scrum Meeting 8