Spring框架常見面試題

Spring 是一種輕量級IoC和AOP容器框架,旨在提高開發人員的開發效率以及系統的可維護性。

我們一般說Spring框架指的是Spring Framework,它是很多模塊的集合,比如核心容器,數據訪問/繼承,web,AOP,工具,消息和測試模塊。Core Container中的Core組件是Spring所有組件的核心,Beans組件和Context組件是實現IOC和DI的基礎,AOP組件用來實現切面編程。
在這裏插入圖片描述

  • Spring Core: 核心組件,Spring其他所有功能都需要依賴該類庫,主要提供IOC功能
  • Spring Context: 提供框架式的Bean訪問方式
  • Spring Aspects:該模塊爲AspectJ的集成提供支持
  • Spring AOP:提供面向切面的編程實現
  • Spring JDBC:JAVA數據庫連接支持
  • Spring JMS:JAVA消息服務
  • Spring ORM:用於支持Hibernate等ORM工具
  • Spring Web:爲創建Web應用程序提供支持
  • Spring Test:提供了對JUnit和TestNG測試的支持

Spring優點

  1. Spring屬於低侵入式設計,代碼的污染極低
  2. Spring的依賴注入機制將對象之間的依賴關係交由框架處理,減低組件耦合性
  3. Spring提供了AOP技術,支持將一些通用任務,如安全、事務、日誌、權限等進行集中式管理,從而提供更好的複用。
  4. spring對於主流的應用框架提供了集成支持。

AOP(Aspect-Oriented Programming): 面向切面編程

作爲面向對象的一種補充,用於將那些與業務無關,但卻對多個對象產生影響的公共行爲和邏輯,抽取並封裝爲一個可重用的模塊,這個模塊被命名爲“切面”,便於減少系統的重複代碼,降低模塊間的耦合。

AOP就是基於動態代理實現的,如果要代理的對象實現了某個接口,那麼Spring AOP會使用JDK 動態代理,去創建代理對象,對於沒有實現接口的目標對象,無法使用JDK代理,會用Cglib代理,這時候會生成一個被代理對象的子類來作爲代理

IOC(Inverse of Control: 控制反轉):

是一種設計思想,利用反射原理,將原本在程序中手動創建對象的控制權轉交給Spring容器管理。IOC容器是Spring用來實現IOC的載體,IOC容器實際上就是個Map(key, value),map中存放的是各種對象。

將對象之間的相互依賴關係交給IOC容器來管理,並由IOC容器完成對象的注入,這樣可以簡化引用的開發,把應用從複雜的依賴關係中解放出來。IOC容器就像一個工廠一樣,當我們需要創建一個對象的時候,只需要配置好配置文件或註解,不用考慮對象如何被創建的。

Spring IOC初始化過程

XML配置文件----讀取—>Resource----解析—>BeanDefinition ----註冊---->BeanFactory

IOC的三種注入方式:構造器注入,setter方法注入,註解注入

spring IOC和DI有什麼區別?

IoC Inverse of Control 反轉控制的概念,就是將原本在程序中手動創建對象的控制權,交由Spring框架管理
DI:Dependency Injection 依賴注入,在Spring框架負責創建Bean對象時,動態的將依賴對象注入到Bean組件

AspectJ

AspectJ是AOP思想的具體實現,但AspectJ相比AOP功能更加強大,AOP只能在由 Spring 容器管理的 bean 上實現而AspectJ可以在所有域對象上實現,AOP僅支持方法執行切入點 AspectJ支持所有切入點。
AOP屬於運行時增強,AspectJ是靜態代理的增強,所謂靜態代理,就是AOP框架會在編譯階段生成AOP代理類,因此也稱爲編譯時增強,AOP基於代理,AspectJ基於字節碼操作,如果我們的切面比較少,那麼兩者性能差異不大,但是切面太多的話,最好選擇AspectJ,他比AOP快很多。原因是AspectJ在編譯時增強,AOP運行時增強。

BeanFactory和ApplicationContext有什麼區別

BeanFactory和ApplicationContext是Spring兩大核心接口,都可以當作Spring的容器,其中ApplicationContext是BeanFactory的子接口

  • BeanFactory:是Spring裏面最底層的接口,包含了各種Bean的定義,讀取bean配置文檔,管理bean的加載、實例化,控制bean的生命週期,維護bean之間的依賴關係
  • 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則是自動註冊。

Spring的作用域

  • Spring的作用域有singleton、prototype、request、session和global session
    • singleton:默認,每一個Spring容器只有一個對象實例
    • prototype:每次請求都會創建一個新的實例
    • request:每一個http請求都會產生一個新的bean實例,該bean僅在當前http request內有效
    • session:每一個HTTP請求都會創建一個新的bean對象,且該對象僅在當前session中有效
    • global session:在一個全局的session中,容器會返回該bean的同一個實例,僅僅在基於portlet容器的web應用中才有意義,spring 5中已經沒有了

Spring中單例bean的線程安全問題

單例bean存在線程安全問題,主要是多線程操作同一個對象的時候,對這個對象的非靜態成員變量的寫操作會存在線程安全問題

解決方式:可以在類中定義一個ThreadLocal成員變量,將需要的可變成員變量保存在ThreadLocal中

Spring中Bean的生命週期

在這裏插入圖片描述

  • 實例化Bean:

    對於BeanFactory容器,當客戶向容器請求一個尚未初始化的bean時,或初始化bean的時候需要注入另一個尚未初始化的依賴時,容器就會調用createBean進行實例化。對於ApplicationContext容器,當容器啓動結束後,通過獲取BeanDefinition對象中的信息,實例化所有的bean。

  • 設置對象屬性(依賴注入)

    實例化後的對象被封裝在BeanWrapper對象中,緊接着,Spring根據BeanDefinition中的信息 以及 通過BeanWrapper提供的設置屬性的接口完成依賴注入。

  • 處理Aware接口

    Spring會檢測該對象是否實現了xxxAware接口,並將相關的xxxAware實例注入給Bean:

    ①如果這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String beanId)方法,此處傳遞的就是Spring配置文件中Bean的id值;

    ②如果這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory()方法,傳遞的是Spring工廠自身。

    ③如果這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文;

  • BeanPostProcessor

    如果想對Bean進行一些自定義的處理,那麼可以讓Bean實現了BeanPostProcessor接口,那將會調用postProcessBeforeInitialization(Object obj, String s)方法。

  • InitializingBean與init-method

    如果Bean在Spring配置文件中配置了 init-method 屬性,則會自動調用其配置的初始化方法

  • 如果這個Bean實現了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法;由於這個方法是在Bean初始化結束時調用的,所以可以被應用於內存或緩存技術;

  • 以上幾個步驟完成後,Bean就已經被正確創建了,之後就可以使用這個Bean了

  • DisposableBean

    當Bean不再需要時,會經過清理階段,如果Bean實現了DisposableBean這個接口,會調用其實現的destroy()方法

  • destroy-method

    最後,如果這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷燬方法

Spring框架中用到了那些設計模式

  • 工廠設計模式:Spring使用工廠模式通過BeanFactory,ApplicationContext創建bean對象
  • 代理設計模式:AOP功能的實現
  • 單例設計模式:Spring中Bean默認都是單例的
  • 模板方法模式:Spring中jdbcTemplate, hibernateTemplate等以Template結尾的對數據庫操作的類,他們就使用到了模板模式
  • 包裝器設計模式:我們項目需要連接多個數據庫,而且不同的客戶在每次訪問中根據需要去訪問不同的數據庫,這種模式能夠讓我們根據客戶的需要動態切換數據源。
  • 觀察者模式:Spring事件驅動模型就是觀察者模式很經典的一個應用
  • 適配器模式:Spring AOP 的增強或通知使用到了適配器模式,SpringMVC中也用到了適配器模式適配Controller

Spring管理事務的方式

Spring事務的本質其實就是數據庫對事務的支持,沒有數據庫的事務支持,spring是無法提供事務功能的。真正的數據庫層的事務提交和回滾是通過binlog或者redo log實現的。

  1. 編程式事務使用TransactionTemplate,在代碼中硬編程,不推薦使用
  2. 聲明式事務,在配置文件中配置,推薦
    • 基於xml的聲明式事務
    • 基於註解的聲明式事務

Spring中事務的隔離級別

TransactionDefinition接口中定義了5個表示隔離級別的常量

  1. TransactionDefinition.ISOLATION_DEFAULT: 默認使用數據庫的隔離級別,Mysql 默認採用的 REPEATABLE_READ隔離級別 Oracle 默認採用的 READ_COMMITTED隔離級別.
  2. TransactionDefinition.ISOLATION_READ_UNCOMMITED: 最低的隔離級別,允許讀取未提交的數據變更,會導致髒讀,不可重複讀,幻讀。
  3. TransactionDefinition.ISOLATION_READ_COMMITED: 允許讀取併發事務已經提交的數據,會導致,不可重複讀,幻讀。
  4. TransactionDefinition.ISOLATION_REPEATABLE_READ: 對同一字段的多次讀取結果都是一致的,除非被本身事務自己所修改,會導致,幻讀。
  5. TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔離級別,完全服從ACID的隔離級別,所有事務依次執行,這樣事務之間就不會產生干擾,但是會嚴重影響程序性能。

Spring事務中的七個傳播機制

  1. 支持當前事務的情況:
    • TransactionDefinition.PROPAGATION_REQUIRED: 如果當前存在事務,加入該事務;如果當前沒有事務,創建一個新的事務
    • TransactionDefinition.PROPAGATION_SUPPORTS: 如果當前存在事務,加入該事務,如果沒有存在事務,則以非事務的方式繼續允許
    • TransactionDefinition.PROPAGATION_MANDATORY(mandatory:強制的):如果當前存在事務,則加入該事務,如果當前沒有事務則拋出異常。
  2. 不支持當前事務的情況:
    • TransactionDefinition.PROPAGATION_REQUIRYES_NEW:創建一個新的事務,如果當前存在事務,則把當前事務掛起
    • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務方式運行,如果當前存在事務則把當前事務掛起
    • TransactionDefinition.PROPAGATION_NEVER: 以非事務方式運行,如果當前存在事務則拋出異常
  3. 其他情況:
    • TransactionDefinition.PROPAGATION_NESTED(nested: 嵌套):如果當前存在事務,則創建 一個事務作爲當前事務的嵌套事務來運行,如果當前沒有事務,則該取值等價於:TransactionDefinition.PROPAGATION_REQUIRED

@Transactional(rollbackFor = Exception.class)註解

我們知道:Exception分爲運行時異常RuntimeException和非運行時異常。事務管理對於企業應用來說是至關重要的,即使出現異常情況,它也可以保證數據的一致性。

@Transactional註解作用於類上時,該類的所有 public 方法將都具有該類型的事務屬性,同時,我們也可以在方法級別使用該標註來覆蓋類級別的定義。如果類或者方法加了這個註解,那麼這個類裏面的方法拋出異常,就會回滾,數據庫裏面的數據也會回滾。

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

Spring框架中有哪些不同類型的事件?

Spring 提供了以下5種標準的事件:

(1)上下文更新事件(ContextRefreshedEvent):在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發。

(2)上下文開始事件(ContextStartedEvent):當容器調用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。

(3)上下文停止事件(ContextStoppedEvent):當容器調用ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。

(4)上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷燬。

(5)請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。

如果一個bean實現了ApplicationListener接口,當一個ApplicationEvent 被髮布以後,bean會自動被通知。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章