Spring全家桶面試題


Spring概述

什么是Spring?

Spring是一個輕量級Java開源框架,最早由Rod Johnson創建,目的是解決企業級應用開發的復雜性,簡化Java開。Spring為開發Java應用程序提供全面的基礎架構支持,因此Java開發者可以專注於應用程序的開發。

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

為了降低Java開發的復雜性,Spring采取了以下4種關鍵策略

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

  • 通過依賴注入和面向接口實現松耦合;

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

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

Spring框架的設計目標,設計理念,和核心是什么

Spring設計目標Spring為開發者提供一個一站式輕量級應用開發平台

Spring設計理念在JavaEE開發中,支持POJO和JavaBean開發方式,使應用面向接口開發,充分支持OO(面向對象)設計方法Spring通過IoC容器實現對象耦合關系的管理,並實現依賴反轉,將對象之間的依賴關系交給IoC容器,實現解耦;

Spring框架的核心IoC容器和AOP模塊通過IoC容器管理POJO對象以及他們之間的耦合關系通過AOP以動態非侵入的方式增強服務,把遍布於應用各層的功能分離出來形成可重用的功能組件

Spring的優缺點是什么?

優點

  • 方便解耦,簡化開發

    Spring就是一個大工廠,可以將所有對象的創建和依賴關系的維護,交給Spring管理。

  • AOP編程的支持

    Spring提供面向切面編程,可以方便的實現對程序進行權限攔截、運行監控等功能。

  • 聲明式事務的支持

    只需要通過配置就可以完成對事務的管理,而無需手動編程。

  • 方便程序的測試

    Spring對Junit4支持,可以通過注解方便的測試Spring程序。

  • 方便集成各種優秀框架

    Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架的直接支持(如:Struts、Hibernate、MyBatis等)。

  • 降低JavaEE API的使用難度

    Spring對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大降低。

缺點

  • Spring明明一個很輕量級的框架,卻給人感覺大而全

  • Spring依賴反射,反射影響性能

  • 使用門檻升高,入門Spring需要較長時間

Spring有哪些應用場景

應用場景:JavaEE企業應用開發,包括SSH、SSM等

Spring價值

  • Spring是非侵入式的框架,目標是使應用程序代碼對框架依賴最小化;

  • Spring提供一個一致的編程模型,使應用直接使用POJO開發,與運行環境隔離開來;

  • Spring推動應用設計風格向面向對象和面向接口開發轉變,提高了代碼的重用性和可測試性;

Spring由哪些模塊組成?

Spring 總共大約有 20 個模塊, 由 1300 多個不同的文件構成。

而這些組件被分別整合在核心容器(Core Container)AOP(Aspect Oriented Programming)和設備支持(Instrumentation)數據訪問與集成(Data Access/Integration)Web消息(Messaging)Test等 6 個模塊中。

以下是 Spring 5 的模塊結構圖:

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

  • spring beans:提供了BeanFactory,是工廠模式的一個經典實現,Spring將管理對象稱為Bean。

  • spring context:構建於 core 封裝包基礎上的 context 封裝包,提供了一種框架式的對象訪問方法。

  • spring jdbc:提供了一個JDBC的抽象層,消除了煩瑣的JDBC編碼和數據庫廠商特有的錯誤代碼解析, 用於簡化JDBC。

  • spring aop:提供了面向切面的編程實現,讓你可以自定義攔截器、切點等。

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

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

Spring 框架中都用到了哪些設計模式?

  1. 工廠模式:BeanFactory就是簡單工廠模式的體現,用來創建對象的實例;

  2. 單例模式:Bean默認為單例模式。

  3. 代理模式:Spring的AOP功能用到了JDK的動態代理和CGLIB字節碼生成技術;

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

  5. 觀察者模式:定義對象間一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象都會得到通知被動更新,如Spring中listener的實現--ApplicationListener。

控制反轉(IOC)

什么是Spring IOC 容器?

控制反轉即IoC (Inversion of Control),它把傳統上由程序代碼直接操控的對象的調用權交給容器,通過容器來實現對象組件的裝配和管理

所謂的“控制反轉”概念就是對對象組件控制權的轉移,從程序代碼本身轉移到了外部容器。

Spring IOC 負責創建對象,管理對象(通過依賴注入(DI),裝配對象,配置對象,並且管理這些對象的整個生命周期。)

控制反轉(IoC)有什么作用

  • 管理對象的創建和依賴關系的維護。對象的創建並不是一件簡單的事,在對象關系比較復雜時,如果依賴關系需要程序猿來維護的話,那是相當頭疼的

  • 解耦,由容器去維護具體的對象

  • 托管了類的整個生命周期,比如我們需要在類的產生過程中做一些處理,最直接的例子就是代理,如果有容器程序可以把這部分處理交給容器,應用程序則無需去關心類是如何完成代理的

Spring IoC 的實現機制

Spring 中的 IoC 的實現原理就是工廠模式加反射機制。

示例:

interface Fruit {
  public abstract void eat();
}

class Apple implements Fruit {
   public void eat(){
       System.out.println("Apple");
  }
}

class Orange implements Fruit {
   public void eat(){
       System.out.println("Orange");
  }
}

class Factory {
   public static Fruit getInstance(String ClassName) {
       Fruit f=null;
       try {
           f=(Fruit)Class.forName(ClassName).newInstance();
      } catch (Exception e) {
           e.printStackTrace();
      }
       return f;
  }
}

class Client {
   public static void main(String[] a) {
       Fruit f=Factory.getInstance("com.jourwon.spring.Apple"); if(f!=null){
           f.eat();
      }
  }
}

BeanFactory 和 ApplicationContext有什么區別?

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

為了更直觀的展示 “低級容器” 和 “高級容器” 的關系,這里通過常用的 ClassPathXmlApplicationContext 類來展示整個容器的層級 UML 關系。

依賴關系

BeanFactory:是Spring里面最底層的接口,包含了各種Bean的定義,讀取bean配置文檔,管理bean的加載、實例化,控制bean的生命周期,維護bean之間的依賴關系。我們可以稱之為 低級容器”

ApplicationContext接口作為BeanFactory的派生,可以稱之為 “高級容器。除了提供BeanFactory所具有的功能外,還提供了更完整的框架功能:

  • 繼承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則是自動注冊。

什么是Spring的依賴注入(Dependency Injection)?

控制反轉IoC是一個很大的概念,可以有不同的實現方式。

其主要實現方式有兩種:依賴注入和依賴查找

依賴注入:相對於IoC而言,依賴注入(DI)更加准確地描述了IoC的設計理念。

所謂依賴注入(Dependency Injection),即組件之間的依賴關系由容器在應用系統運行期來決定,也就是由容器動態地將某種依賴關系的目標對象實例注入到應用系統中的各個關聯的組件之中。組件不做定位查詢,只提供普通的Java方法,讓容器去決定依賴關系。

依賴查找(Dependency Lookup):容器提供回調接口和上下文環境給組件。EJB和Apache Avalon都使用這種方式。

依賴查找也有兩種類型:依賴拖拽(DP)和上下文依賴查找(CDL)。

有哪些不同類型的依賴注入實現方式?

依賴注入是時下最流行的IoC實現方式依賴注入分為接口注入(Interface Injection),Setter方法注入(Setter Injection)和構造器注入(Constructor Injection)三種方式

其中接口注入由於在靈活性和易用性比較差,現在從Spring4開始已被廢棄。

構造器注入構造器注入是容器通過調用一個類的構造器來實現的,該構造器有一系列參數,每個參數都必須注入。

Setter方法注入Setter方法注入是容器通過調用無參構造器或無參static工廠方法實例化bean之后,調用該bean的setter方法來實現的依賴注入。

 

構造器注入和 Setter方法注入的區別

  構造器注入 setter 注入
部分注入 沒有部分注入 有部分注入
覆蓋setter屬性 不會覆蓋 setter 屬性 會覆蓋 setter 屬性
任意修改是否創建新實例 任意修改都會創建一個新實例 任意修改不會創建一個新實例
適用場景 適用於設置很多屬性 適用於設置少量屬性

最好的解決方案是用構造器參數實現強制依賴,setter方法實現可選依賴。

面向切面編程(AOP)

什么是AOP

OOP(Object-Oriented Programming)面向對象編程,允許開發者定義縱向的關系,但並不適用於定義橫向的關系,導致了大量重復代碼,而不利於各個模塊的重用。

AOP(Aspect-Oriented Programming),一般稱為面向切面編程,作為面向對象的一種補充,用於將那些與業務無關,但卻對多個對象產生影響的公共行為和邏輯,抽取並封裝為一個可重用的模塊

這個模塊被命名為“切面”(Aspect),通過面向切面編程減少了系統中的重復代碼,降低了模塊間的耦合度,同時提高了系統的可維護性

常用於權限認證、日志、事務處理等。

Spring AOP and AspectJ AOP 有什么區別?AOP 有哪些實現方式?

AOP實現的關鍵在於代理模式,AOP代理主要分為靜態代理和動態代理。靜態代理的代表為AspectJ;動態代理則以Spring AOP為代表

(1)AspectJ是靜態代理的增強,所謂靜態代理,就是AOP框架會在編譯階段生成AOP代理類,因此也稱為編譯時增強他會在編譯階段將AspectJ(切面)織入到Java字節碼中,運行的時候就是增強之后的AOP對象。

(2)Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼而是每次運行時在內存中臨時為方法生成一個AOP對象,這個AOP對象包含了目標對象的全部方法,並且在特定的切點做了增強處理,並回調原對象的方法

JDK動態代理和CGLIB動態代理的區別

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

  • JDK動態代理只提供接口的代理,不支持類的代理核心InvocationHandler接口和Proxy類,InvocationHandler 通過invoke()方法反射來調用目標類中的代碼,動態地將橫切邏輯和業務編織在一起接着,Proxy利用 InvocationHandler動態創建一個符合某一接口的的實例,  生成目標類的代理對象。

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

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

InvocationHandler 的 invoke(Object  proxy,Method  method,Object[] args):

proxy是最終生成的代理實例;  method 是被代理目標實例的某個具體方法;  args 是被代理目標實例某個方法的具體入參, 在方法反射調用時使用。

解釋一下Spring AOP里面的幾個名詞

(1)切面(Aspect):切面是通知和切點的結合。通知和切點共同定義了切面的全部內容。在Spring AOP中,切面可以使用通用類(基於模式的風格) 或者在普通類中以 @AspectJ 注解來實現。

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

(3)通知(Advice):在AOP術語中,切面的工作被稱為通知。

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

(5)引入(Introduction):引入允許我們向現有類添加新方法或屬性。

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

(7)織入(Weaving):織入是把切面應用到目標對象並創建新的代理對象的過程。在目標對象的生命周期里有多少個點可以進行織入:

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

  • 類加載期:切面在目標類加載到JVM時被織入。需要特殊的類加載器,它可以在目標類被引入應用之前增強該目標類的字節碼。AspectJ5的加載時織入就支持以這種方式織入切面。

  • 運行期:切面在應用運行的某個時刻被織入。一般情況下,在織入切面時,AOP容器會為目標對象動態地創建一個代理對象。SpringAOP就是以這種方式織入切面。

Spring通知有哪些類型?

在AOP術語中,切面的工作被稱為通知,實際上是程序執行時要通過SpringAOP框架觸發的代碼段。

以下是Spring定義的五種通知和常見使用場景

通知類型 說明 使用場景
前置通知(Before) 在目標方法被執行之前調用通知  
后置通知(After) 無論如何都會在目標方法執行之后調用通知 記錄日志(方法已經調用,但不一定成功)
返回通知(After-returning ) 在目標方法正常返回后執行通知,如果方法沒有正常返返回,例如拋出異常,則返回通知不會執行,可以通過配置得到目標方法的返回值 記錄日志(方法已經成功調用)
異常通知(After-throwing) 在目標方法拋出異常后調用通知 異常處理
環繞通知(Around) 通知包裹了目標方法,在目標方法調用之前和調用之后執行自定義的行為 事務權限控制

Spring Beans

解釋Spring支持的幾種bean的作用域

當定義一個bean在Spring里,我們還能給這個bean聲明一個作用域。它可以通過bean的scope屬性來定義。

Spring框架支持以下五種bean的作用域:

作用域 描述
singleton 單例模式,在spring IoC容器僅存在一個Bean實例,默認值
prototype 原型模式,每次從容器中獲取Bean時,都返回一個新的實例,即每次調用getBean()時,相當於執行newXxxBean()
request 每次HTTP請求都會創建一個新的Bean,該作用域僅在基於web的Spring ApplicationContext環境下有效
session 同一個HTTP Session共享一個Bean,不同Session使用不同的Bean,該作用域僅在基於web的Spring ApplicationContext環境下有效
global-session 同一個全局的HTTP Session中共享一個Bean,一般用於Portlet應用環境,該作用域僅在基於web的Spring ApplicationContext環境下有效

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

Spring框架中的單例bean是線程安全的嗎?

不是,Spring框架中的單例bean不是線程安全的。

spring 中的 bean 默認是單例模式,spring 框架並沒有對單例 bean 進行多線程的封裝處理。

實際上大部分時候 spring bean 是無狀態的(比如 dao 類),所以某種程度上來說 bean 也是安全的

如果 bean 有狀態的話(比如 view model 對象),那就要開發者自己去保證線程安全了,最簡單的就是改變 bean 的作用域,把“singleton”變更為“prototype”,這樣請求 bean 相當於 new Bean()了,所以就可以保證線程安全了。

有狀態和無狀態區別

  • 有狀態就是有數據存儲功能。

  • 無狀態就是不會保存數據。

Spring如何處理線程並發問題?

在一般情況下,只有無狀態的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域,因為Spring對一些Bean中非線程安全狀態采用ThreadLocal進行處理,解決線程安全問題。

ThreadLocal和線程同步機制都是為了解決多線程中共享變量的訪問沖突問題。同步機制采用了“時間換空間”的方式,僅提供一份變量,不同的線程在訪問前需要獲取鎖,沒獲得鎖的線程則需要排隊。而ThreadLocal采用了“空間換時間”的方式。

ThreadLocal會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。

解釋Spring框架中bean的生命周期

在傳統的Java應用中,bean的生命周期很簡單。

使用Java關鍵字new進行bean實例化,然后該bean就可以使用了。一旦該bean不再被使用,則由Java自動進行垃圾回收。

相比之下,Spring容器中的bean的生命周期就顯得相對復雜多了。

正確理解Spring bean的生命周期非常重要,因為你或許要利用Spring提供的擴展點來自定義bean的創建過程。

下圖展示了bean裝載到Spring應用上下文中的一個典型的生命周期過程。

bean在Spring容器中從創建到銷毀經歷了若干階段,每一階段都可以針對Spring如何管理bean進行個性化定制。

正如你所見,在bean准備就緒之前,bean工廠執行了若干啟動步驟。

我們對上圖進行詳細描述:

  Spring對bean進行實例化;

  Spring將值和bean的引用注入到bean對應的屬性中;

  如果bean實現了BeanNameAware接口,Spring將bean的ID傳遞給setBean-Name()方法;

  如果bean實現了BeanFactoryAware接口,Spring將調用setBeanFactory()方法,將BeanFactory容器實例傳入;

  如果bean實現了ApplicationContextAware接口,Spring將調用setApplicationContext()方法,將bean所在的應用上下文的引用傳入進來;

  如果bean實現了BeanPostProcessor接口,Spring將調用它們的post-ProcessBeforeInitialization()方法;

  如果bean實現了InitializingBean接口,Spring將調用它們的after-PropertiesSet()方法。類似地,如果bean使用initmethod聲明了初始化方法,該方法也會被調用;

  此時,bean已經准備就緒,可以被應用程序使用了,它們將一直駐留在應用上下文中,直到該應用上下文被銷毀;

  如果bean實現了DisposableBean接口,Spring將調用它的destroy()接口方法。同樣,如果bean使用destroy-method聲明了銷毀方法,該方法也會被調用。

現在你已經了解了如何創建和加載一個Spring容器。但是一個空的容器並沒有太大的價值,在你把東西放進去之前,它里面什么都沒有。為了從Spring的DI(依賴注入)中受益,我們必須將應用對象裝配進Spring容器中。

Spring注解

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

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

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

然后在啟動spring IoC時,容器就會自動裝載了一個AutowiredAnnotationBeanPostProcessor后置處理器,

當容器掃描到@Autowied、@Resource或@Inject時,就會在IoC容器自動查找需要的bean,並裝配給該對象的屬性

在使用@Autowired時,首先在容器中查詢對應類型的bean:

  • 如果查詢結果剛好為一個,就將該bean裝配給@Autowired指定的屬性;

  • 如果查詢的結果不止一個,會拋出異常,需要配合@Qualifier注解根據名稱來查找;

  • 如果配合@Qualifier注解根據名稱來查找的結果為空,會拋出異常,可以將@Autowire注解的required屬性設置為false。

@Autowired和@Resource之間的區別

@Autowired和@Resource都可用於:構造函數、Setter方法、成員變量 ,都可以用來裝配bean

@Autowired和@Resource之間的區別

  • @Autowired默認按類型裝配(這個注解是屬於spring的),@Resource 是JDK1.6支持的注解,默認按照名稱進行裝配

 

  • @Autowired默認情況下必須要求依賴對象必須存在,如果要允許null值,可以設置它的required屬性為false,如:@Autowired(required=false) ,如果我們想使用名稱裝配可以結合@Qualifier注解進行使用
@Autowired
@Qualifier("baseDao")
private BaseDao baseDao;
  • Resource名稱可以通過name屬性進行指定如果沒有指定name屬性,當注解寫在字段上時,默認取字段名,按照名稱查找,如果注解寫在setter方法上默認取屬性名進行裝配當找不到與名稱匹配的bean時才按照類型進行裝配。但是需要注意的是,如果name屬性一旦指定,就只會按照名稱進行裝配。
@Resource(name="baseDao")
private BaseDao baseDao;

 

  • 其實@Autowired + @Qualifier("BWM") == @Resource(name="BWM")如果當一個接口只有一個實現類,使用@Autowired和@Resource沒有區別,但是最好用@Autowired

@Component, @Controller, @Service, @Repository有何區別?

這四個注解都可以將bean注入到spring容器中,根據不同的使用場景定義了特定功能的注解組件

@Controller用於標注控制層組件

@Service用於標注業務層組件

@Repository用於標注數據訪問層組件,即DAO組件

@Component泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注

數據訪問

Spring支持的事務管理類型, Spring事務實現方式有哪些?你更傾向用哪種事務管理類型?

Spring支持兩種類型的事務管理

編程式事務管理通過編程的方式管理事務,靈活性好,但是難維護。

聲明式事務管理將業務代碼和事務管理分離,只需用注解和XML配置來管理事務。

大多數情況下選擇聲明式事務管理,雖然比編程式事務管理少了一點靈活性,最細粒度只能作用到方法級別,無法做到像編程式事務那樣可以作用到代碼塊級別,

但是聲明式事務管理對應用代碼的影響最小,更符合一個無侵入的輕量級容器的思想,具有更好的可維護性。

Spring事務的實現方式和實現原理

Spring事務的本質其實就是數據庫對事務的支持,沒有數據庫的事務支持,spring是無法提供事務功能的。

真正的數據庫層的事務提交和回滾是通過bin log或者redo log實現的。

說一下Spring的事務傳播行為

spring事務的傳播行為說的是,當多個事務同時存在的時候,spring如何處理這些事務的行為。

PROPAGATION_REQUIRED如果當前沒有事務,就創建一個新事務,如果當前存在事務,就加入該事務,該設置是最常用的設置

PROPAGATION_SUPPORTS支持當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就以非事務執行。

③ PROPAGATION_MANDATORY:支持當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就拋出異常。

PROPAGATION_REQUIRES_NEW創建新事務,無論當前存不存在事務,都創建新事務。

⑤ PROPAGATION_NOT_SUPPORTED:以非事務方式執行,如果當前存在事務,就把當前事務掛起。

⑥ PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則拋出異常。

⑦ PROPAGATION_NESTED:如果當前存在事務,則在嵌套事務內執行如果當前沒有事務,則按REQUIRED屬性執行。

說一下 spring 的事務隔離級別?

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

  1. ISOLATION_DEFAULT用底層數據庫的設置隔離級別,數據庫設置的是什么我就用什么;

  2. ISOLATION_READ_UNCOMMITTED讀未提交,最低的隔離級別,一個事務可以讀取另一個事務更新但未提交的數據。(會出現臟讀、不可重復讀、幻讀);

  3. ISOLATION_READ_COMMITTED讀已提交,一個事務提交后才能被其他事務讀取到(會出現不可重復讀、幻讀),Oracle、SQL server 的默認級別;

  4. ISOLATION_REPEATABLE_READ可重復讀,對同一字段的多次讀取結果都是一致的,除非數據被本身事務所修改(會出現幻讀),MySQL 的默認級別;

  5. ISOLATION_SERIALIZABLE可串行化,最高的隔離級別,可以防止臟讀、不可重復讀、幻讀。

Spring框架的事務管理有哪些優點?

  • 為不同的事務API  如 JTA,JDBC,Hibernate,JPA 和JDO,提供一個不變的編程模式。

  • 為編程式事務管理提供了一套簡單的API而不是一些復雜的事務API

  • 支持聲明式事務管理。

  • 和Spring各種數據訪問抽象層很好得集成。

 

Spring MVC

@$什么是Spring MVC?簡單介紹下你對Spring MVC的理解?

Spring MVC是一個基於Java,實現了MVC設計模式的請求驅動類型的輕量級Web框架,通過把模型-視圖-控制器分離,將web層進行職責解耦,把復雜的web應用分成邏輯清晰的幾部分,簡化開發,減少出錯,方便組內開發人員之間的配合。

 

Spring MVC的優點

(1)可以支持各種視圖技術,而不僅僅局限於JSP;

(2)與Spring框架集成(如IoC容器、AOP等);

(3)清晰的角色分配:前端控制器(dispatcherServlet) , 處理器映射器(handlerMapping),處理器適配器(HandlerAdapter),視圖解析器(ViewResolver)。

(4) 支持各種請求資源的映射策略。

Spring MVC的主要組件?

(1)前端控制器 DispatcherServlet(不需要程序員開發)

作用:接收請求、響應結果,相當於轉發器,有了DispatcherServlet 就減少了其它組件之間的耦合度。

(2)處理器映射器HandlerMapping(不需要程序員開發)

作用:根據請求的URL來查找Handler

(3)處理器適配器HandlerAdapter

注意:在編寫Handler的時候要按照HandlerAdapter要求的規則去編寫,這樣適配器HandlerAdapter才可以正確的去執行Handler。

(4)處理器Handler(需要程序員開發)

(5)視圖解析器 ViewResolver(不需要程序員開發)

作用:進行視圖的解析,根據視圖邏輯名解析成真正的視圖(view)

(6)視圖View(需要程序員開發jsp)

View是一個接口, 它的實現類支持不同的視圖類型(jsp,freemarker,pdf等等)

請描述Spring MVC的工作流程?描述一下 DispatcherServlet 的工作流程?

(1)用戶發送請求至前端控制器DispatcherServlet;

(2) DispatcherServlet收到請求后,調用HandlerMapping處理器映射器,請求獲取Handler;

(3)處理器映射器根據請求url找到具體的處理器,生成處理器對象及處理器攔截器(如果有則生成)一並返回給DispatcherServlet;

(4)DispatcherServlet 調用 HandlerAdapter處理器適配器;

(5)HandlerAdapter 經過適配調用 具體處理器(Handler,也叫后端控制器);

(6)Handler執行完成返回ModelAndView;

(7)HandlerAdapter將Handler執行結果ModelAndView返回給DispatcherServlet;

(8)DispatcherServlet將ModelAndView傳給ViewResolver視圖解析器進行解析;

(9)ViewResolver解析后返回具體View;

(10)DispatcherServlet對View進行渲染視圖(即將模型數據填充至視圖中)

(11)DispatcherServlet響應用戶。

MVC是什么?MVC設計模式的好處有哪些

mvc是一種設計模式(設計模式就是日常開發中編寫代碼的一種好的方法和經驗的總結)。

模型(model)-視圖(view)-控制器(controller),三層架構的設計模式。用於實現前端頁面的展現與后端業務數據處理的分離。

mvc設計模式的好處

  1. 分層設計,實現了業務系統各個組件之間的解耦,有利於業務系統的可擴展性,可維護性。

  2. 有利於系統的並行開發,提升開發效率。

攔截器Interceptor與過濾器Filter的區別

攔截器和過濾器的區別

類型 過濾器Filter 攔截器interceptor
規范 Filter是在Servlet規范中定義的,是Servlet容器支持的 攔截器是在Spring容器內的,是Spring框架支持的
使用范圍 過濾器只能用於Web程序中 攔截器既可以用於Web程序,也可以用於Application、Swing程序中
原理 過濾器是基於函數回調 攔截器是基於java的反射機制
使用的資源 過濾器不能使用Spring資源 攔截器是一個Spring的組件,歸Spring管理,配置在Spring文件中,因此能使用Spring里的任何資源、對象,例如Service對象、數據源、事務管理等,可以通過loC注入到攔截器
深度 Filter在只在Servlet前后起作用 攔截器能夠深入到方法前后、異常拋出前后等,因此攔截器的使用具有更大的彈性

在Tomcat容器中,過濾器和攔截器觸發時機不一樣過濾器是在請求進入容器后,但請求進入servlet之前進行預處理的。請求結束返回也是,是在servlet處理完后,返回給前端之前。過濾器包裹住servlet,servlet包裹住攔截器

Spring MVC與Struts2區別

相同點

都是基於mvc設計模式的web框架,都用於web項目的開發。在企業項目中,Spring MVC使用更多一些。

不同點

類型 Spring MVC Struts2
前端控制器 Spring MVC的前端控制器是servlet:DispatcherServlet Struts2的前端控制器是filter:StrutsPreparedAndExcutorFilter
攔截機制和請求參數的接受方式 Spring MVC是方法級別的攔截,一個方法對應一個request上下文。Spring MVC是使用方法的形參接收請求的參數,基於方法的開發,線程安全,單例模式 Struts2框架是類級別的攔截,每次請求就會創建一個Action,一個Action對應一個request上下文。Struts2是通過類的成員變量接收請求的參數,是基於類的開發,線程不安全,多例模式
配置和性能 配置少,開發效率和性能高於Struts2 配置多,開發效率和性能低於Spring MVC
與Spring框架的整合 Spring MVC是Spring框架的一部分,無縫整合 Struts2與Spring整合相對麻煩

 

Spring Boot

什么是 Spring Boot?

Spring Boot 是 Spring 開源組織下的子項目,是 Spring 組件一站式解決方案,主要是簡化了使用 Spring 的難度,簡化了繁重的配置,提供了各種啟動器,開發者能快速上手。

Spring Boot 有哪些優點?

Spring Boot 主要有如下優點:

  1. 容易上手,提升開發效率,為 Spring 開發提供一個更快、更廣泛的入門體驗。

  2. 開箱即用,遠離繁瑣的配置。

  3. 沒有代碼生成,也不需要XML配置。

  4. 提供了一系列大型項目通用的非業務性功能,例如:內嵌服務器、安全管理、運行數據監控、運行狀況檢查和外部化配置等。

  5. 避免大量的 Maven 導入和各種版本沖突。

Spring Boot的啟動流程

Spring Boot 入口——main方法

@SpringBootApplication
public class Application {
   public static void main(String[] args) throws Exception {
       SpringApplication.run(Application.class, args);
  }
}

從上面代碼可以看出,Annotation定義(@SpringBootApplication)和類定義(SpringApplication.run)最為耀眼,所以分析 Spring Boot 啟動過程,我們就從這兩方面開始。

從源碼聲明可以看出,@SpringBootApplication相當於 @SpringBootConfiguration + @ComponentScan +  @EnableAutoConfiguration ,因此我們直接拆開來分析。

上面三個注解都在做一件事:注冊bean到spring容器。他們通過不同的條件不同的方式來完成:

  • @SpringBootConfiguration 通過與 @Bean 結合完成Bean的 JavaConfig 配置;

  • @ComponentScan 通過范圍掃描的方式,掃描特定注解注釋的類,將其注冊到Spring容器;

  • @EnableAutoConfiguration 通過 spring.factories 的配置,並結合 @Condition 條件,完成bean的注冊;

除了上面的三個注解,還可以使用@Import注解將bean注冊到Spring容器

  • @Import 通過導入的方式,將指定的class注冊解析到Spring容器;

 

Spring Boot 啟動流程

SpringApplication的實例化

  • 推斷應用類型是否是Web環境

  • 設置初始化器(Initializer)

  • 設置監聽器(Listener)

  • 推斷應用入口類(Main)

SpringApplication.run方法

  • 獲取SpringApplicationRunListeners

  • 准備配置環境ConfigurableEnvironment

  • 創建ApplicationContext應用上下文

  • ApplicationContext前置處理

  • ApplicationContext刷新

  • ApplicationContext后置處理

完成了實例化,下面開始調用run方法

// 運行run方法
public ConfigurableApplicationContext run(String... args) {
   // 此類通常用於監控開發過程中的性能,而不是生產應用程序的一部分。
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();

   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

   // 設置java.awt.headless系統屬性,默認為true
   // Headless模式是系統的一種配置模式。在該模式下,系統缺少了顯示設備、鍵盤或鼠標。
   configureHeadlessProperty();

   // KEY 1 - 獲取SpringApplicationRunListeners
   SpringApplicationRunListeners listeners = getRunListeners(args);

   // 通知監聽者,開始啟動
   listeners.starting();
   try {
       ApplicationArguments applicationArguments = new DefaultApplicationArguments(
               args);

       // KEY 2 - 根據SpringApplicationRunListeners以及參數來准備環境
       ConfigurableEnvironment environment = prepareEnvironment(listeners,
               applicationArguments);
       
       configureIgnoreBeanInfo(environment);

       // 准備Banner打印器 - 就是啟動Spring Boot的時候打印在console上的ASCII藝術字體
       Banner printedBanner = printBanner(environment);

       // KEY 3 - 創建Spring上下文
       context = createApplicationContext();

       // 注冊異常分析器
       analyzers = new FailureAnalyzers(context);

       // KEY 4 - Spring上下文前置處理
       prepareContext(context, environment, listeners, applicationArguments,
               printedBanner);

       // KEY 5 - Spring上下文刷新
       refreshContext(context);

       // KEY 6 - Spring上下文后置處理
       afterRefresh(context, applicationArguments);

       // 發出結束執行的事件
       listeners.finished(context, null);

       stopWatch.stop();
       if (this.logStartupInfo) {
           new StartupInfoLogger(this.mainApplicationClass)
                  .logStarted(getApplicationLog(), stopWatch);
      }
       return context;
  }
   catch (Throwable ex) {
       handleRunFailure(context, listeners, exceptionReporters, ex);
       throw new IllegalStateException(ex);
  }
}

Spring Boot Starter是什么?如何自定義Spring Boot Starter

Spring boot之所以流行,很大原因是因為有Spring Boot Starter。Spring Boot Starter是Spring boot的核心,可以理解為一個可拔插式的插件,例如,你想使用Reids插件,那么可以導入spring-boot-starter-redis依賴

Starter的命名

官方對Starter項目的jar包定義的 artifactId 是有要求的,當然也可以不遵守。

Spring官方Starter通常命名為spring-boot-starter-{name}如:spring-boot-starter-web,

Spring官方建議非官方的starter命名應遵守{name}-spring-boot-starter的格式。

傳統的做法

在沒有starter之前,假如我想要在Spring中使用jpa,那我可能需要做以下操作:

  1. 在Maven中引入使用的數據庫的依賴(即JDBC的jar)

  2. 引入jpa的依賴

  3. 在xxx.xml中配置一些屬性信息

  4. 反復的調試直到可以正常運行

需要注意的是,這里操作在我們次新建一個需要用到jpa的項目都需要重復的做一次

使用Spring Boot Starter可以提升效率

starter的主要目的就是為了解決上面的這些問題。

使用starter的好處,starter的作用:

  • 幫助用戶去除了繁瑣的重復性的構建操作

  • 在“約定大於配置”的理念下,ConfigurationProperties還幫助用戶減少了無謂的配置操作

  • 因為 application.properties 文件的存在,用戶可以集中管理自定義配置

創建自己的Spring Boot Starter

如果你想要自己創建一個starter,那么基本上包含以下幾步

  1. 新建一個Maven項目,在pom.xml文件中定義好所需依賴;

  2. 新建配置類,寫好配置項和默認值,使用@ConfigurationProperties指明配置項前綴;

  3. 新建自動裝配類,使用@Configuration@Bean來進行自動裝配;

  4. spring.factories文件,用於指定自動裝配類的路徑;

  5. 將starter安裝到maven倉庫,讓其他項目能夠引用

spring.factories文件位於resources/META-INF目錄下,需要手動創建;org.springframework.boot.autoconfigure.EnableAutoConfiguration后面的類名說明了自動裝配類,如果有多個 ,則用逗號分開;

使用者應用(SpringBoot)在啟動的時候,會通過org.springframework.core.io.support.SpringFactoriesLoader讀取classpath下每個Starter的spring.factories文件,加載自動裝配類進行Bean的自動裝配;

什么是 JavaConfig?

Spring JavaConfig 是 Spring 社區的產品,它提供了使用注釋來配置Bean的純 Java 方法。因此它有助於避免使用 XML 配置。使用 JavaConfig 的優點在於:

(1)面向對象的配置。由於配置被定義為 JavaConfig 中的類,因此用戶可以充分利用 Java 中的面向對象功能。一個配置類可以繼承另一個,重寫它的@Bean 方法等。

(2)減少或消除 XML 配置。基於依賴注入原則的外部配置的好處已被證明。但是,許多開發人員不希望在 XML 和 Java 之間來回切換。JavaConfig 為開發人員提供了一種純 Java 方法來配置與 XML 配置概念相似的 Spring 容器。從技術角度來講,只使用 JavaConfig 配置類來配置容器是可行的,但實際上很多人認為將JavaConfig 與 XML 混合匹配是理想的。

(3)類型安全和重構友好。JavaConfig 提供了一種類型安全的方法來配置 Spring容器。由於 Java 5.0 對泛型的支持,現在可以按類型而不是按名稱檢索 bean,不需要任何強制轉換或基於字符串的查找。

spring boot 核心配置文件是什么?bootstrap.properties 和 application.properties 有何區別 ?

單純做 Spring Boot 開發,不太容易遇到 bootstrap.properties 配置文件,但是在結合 Spring Cloud 時,這個配置就會經常遇到了,特別是在需要加載一些遠程配置文件的時侯。

spring boot 核心的兩個配置文件:

  • bootstrap (. yml 或者 . properties):bootstrap 由父 ApplicationContext 加載的,比 applicaton 優先加載,配置在應用程序上下文的引導階段生效。一般來說我們在 Spring Cloud Config 或者 Nacos 中會用到它。且 bootstrap 里面的屬性不能被覆蓋;

  • application (. yml 或者 . properties):由ApplicatonContext 加載,用於 spring boot 項目的自動化配置。

什么是 Spring Profiles?

Spring Profiles 主要有下面兩個使用場景:

  • 根據不同的使用環境定義不同的profiles文件,比如開發,測試和生產,可以大大省去我們修改配置信息而帶來的煩惱

  • 根據不同的profiles(dev,test,prod)注冊不同的bean,當應用程序在開發中運行時,只有某些 bean 可以加載,而在生產中,某些其他 bean 可以加載

Spring Boot Starter是什么?如何自定義Spring Boot Starter

Spring boot之所以流行,很大原因是因為有Spring Boot Starter。Spring Boot Starter是Spring boot的核心,可以理解為一個可拔插式的插件,例如,你想使用Reids插件,那么可以導入spring-boot-starter-redis依賴

Starter的命名

官方對Starter項目的jar包定義的 artifactId 是有要求的,當然也可以不遵守。Spring官方Starter通常命名為spring-boot-starter-{name}如:spring-boot-starter-web,Spring官方建議非官方的starter命名應遵守{name}-spring-boot-starter的格式。

傳統的做法

在沒有starter之前,假如我想要在Spring中使用jpa,那我可能需要做以下操作:

  1. 在Maven中引入使用的數據庫的依賴(即JDBC的jar)

  2. 引入jpa的依賴

  3. 在xxx.xml中配置一些屬性信息

  4. 反復的調試直到可以正常運行

需要注意的是,這里操作在我們每次新建一個需要用到jpa的項目都需要重復的做一次

使用Spring Boot Starter可以提升效率

starter的主要目的就是為了解決上面的這些問題。

使用starter的好處,starter的作用:

  • 幫助用戶去除了繁瑣的重復性的構建操作

  • 在“約定大於配置”的理念下,ConfigurationProperties還幫助用戶減少了無謂的配置操作

  • 因為 application.properties 文件的存在,用戶可以集中管理自定義配置

創建自己的Spring Boot Starter

如果你想要自己創建一個starter,那么基本上包含以下幾步

  1. 新建一個Maven項目,在pom.xml文件中定義好所需依賴;

  2. 新建配置類,寫好配置項和默認值,使用@ConfigurationProperties指明配置項前綴;

  3. 新建自動裝配類,使用@Configuration@Bean來進行自動裝配;

  4. 新建spring.factories文件,用於指定自動裝配類的路徑;

  5. 將starter安裝到maven倉庫,讓其他項目能夠引用

spring.factories文件位於resources/META-INF目錄下,需要手動創建;org.springframework.boot.autoconfigure.EnableAutoConfiguration后面的類名說明了自動裝配類,如果有多個 ,則用逗號分開;使用者應用(SpringBoot)在啟動的時候,會通過org.springframework.core.io.support.SpringFactoriesLoader讀取classpath下每個Starter的spring.factories文件,加載自動裝配類進行Bean的自動裝配;

 

什么是 JavaConfig?

Spring JavaConfig 是 Spring 社區的產品,它提供了使用注釋來配置Bean的純 Java 方法。因此它有助於避免使用 XML 配置。使用 JavaConfig 的優點在於:

(1)面向對象的配置。由於配置被定義為 JavaConfig 中的類,因此用戶可以充分利用 Java 中的面向對象功能。一個配置類可以繼承另一個,重寫它的@Bean 方法等。

(2)減少或消除 XML 配置。基於依賴注入原則的外部配置的好處已被證明。但是,許多開發人員不希望在 XML 和 Java 之間來回切換。JavaConfig 為開發人員提供了一種純 Java 方法來配置與 XML 配置概念相似的 Spring 容器。從技術角度來講,只使用 JavaConfig 配置類來配置容器是可行的,但實際上很多人認為將JavaConfig 與 XML 混合匹配是理想的。

(3)類型安全和重構友好。JavaConfig 提供了一種類型安全的方法來配置 Spring容器。由於 Java 5.0 對泛型的支持,現在可以按類型而不是按名稱檢索 bean,不需要任何強制轉換或基於字符串的查找。

spring boot 核心配置文件是什么?bootstrap.properties 和 application.properties 有何區別 ?

單純做 Spring Boot 開發,不太容易遇到 bootstrap.properties 配置文件,但是在結合 Spring Cloud 時,這個配置就會經常遇到了,特別是在需要加載一些遠程配置文件的時侯。

spring boot 核心的兩個配置文件:

  • bootstrap (. yml 或者 . properties):bootstrap 由父 ApplicationContext 加載的,比 applicaton 優先加載,配置在應用程序上下文的引導階段生效。一般來說我們在 Spring Cloud Config 或者 Nacos 中會用到它。且 bootstrap 里面的屬性不能被覆蓋;

  • application (. yml 或者 . properties):由ApplicatonContext 加載,用於 spring boot 項目的自動化配置

什么是 Spring Profiles?

Spring Profiles 主要有下面兩個使用場景:

  • 根據不同的使用環境定義不同的profiles文件,比如開發,測試和生產,可以大大省去我們修改配置信息而帶來的煩惱

  • 根據不同的profiles(dev,test,prod)注冊不同的bean,當應用程序在開發中運行時,只有某些 bean 可以加載,而在生產中,某些其他 bean 可以加載

spring-boot-starter-parent 有什么用 ?

我們都知道,新創建一個 Spring Boot 項目,默認都是有 parent 的,這個 parent 就是 spring-boot-starter-parent ,spring-boot-starter-parent 主要有如下作用:

  1. 定義了 Java 編譯版本為 1.8 。

  2. 使用 UTF-8 格式編碼

  3. 繼承自 spring-boot-dependencies,這個里邊定義了依賴的版本,也正是因為繼承了這個依賴,所以我們在寫依賴時才不需要寫版本號。

  4. 執行打包操作的配置。

  5. 自動化的資源過濾。

  6. 自動化的插件配置。

  7. 針對 application.properties 和 application.yml 的資源過濾,包括通過 profile 定義的不同環境的配置文件,例如 application-dev.properties 和 application-dev.yml。

Spring Boot 打成的 jar 和普通的 jar 有什么區別 ?

Spring Boot 項目最終打包成的 jar 是可執行 jar ,這種 jar 可以直接通過 java -jar xxx.jar 命令來運行,這種 jar 不可以作為普通的 jar 被其他項目依賴,即使依賴了也無法使用其中的類。

Spring Boot 的 jar 無法被其他項目依賴,主要還是他和普通 jar 的結構不同

普通的 jar 包,解壓后直接就是包名,包里就是我們的代碼,而 Spring Boot 打包成的可執行 jar 解壓后,在 \BOOT-INF\classes 目錄下才是我們的代碼,因此無法被直接引用

如果非要引用,可以在 pom.xml 文件中增加配置,將 Spring Boot 項目打包成兩個 jar ,一個可執行,一個可引用。

Spring Boot 中如何解決跨域問題 ?

跨域可以在前端通過 JSONP 來解決,但是 JSONP 只可以發送 GET 請求,無法發送其他類型的請求,在 RESTful 風格的應用中,就顯得非常雞肋,因此我們推薦在后端通過 (CORS,Cross-origin resource sharing) 來解決跨域問題。

這種解決方案並非 Spring Boot 特有的,在傳統的 SSM 框架中,就可以通過 CORS 來解決跨域問題,只不過之前我們是在 XML 文件中配置 CORS ,

現在可以通過實現WebMvcConfigurer接口然后重寫addCorsMappings方法解決跨域問題。

@Configuration
public class CorsConfig implements WebMvcConfigurer {

   @Override
   public void addCorsMappings(CorsRegistry registry) {
       registry.addMapping("/**")
              .allowedOrigins("*")
              .allowCredentials(true)
              .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
              .maxAge(3600);
  }

}

使用上面的方式解決跨域會有點問題,具體描述如下

我們使用cookie存放用戶登錄的信息,在spring攔截器進行權限控制,當權限不符合時,直接返回給用戶固定的json結果。

當用戶登錄以后,正常使用;當用戶退出登錄狀態時或者token過期時,由於攔截器和跨域的順序有問題,出現了跨域的現象。

我們知道一個http請求,先走filter,到達servlet后才進行攔截器的處理,如果我們把cors放在filter里,就可以優先於權限攔截器執行。

@Configuration
public class CorsConfig {

   @Bean
   public CorsFilter corsFilter() {
       CorsConfiguration corsConfiguration = new CorsConfiguration();
       corsConfiguration.addAllowedOrigin("*");
       corsConfiguration.addAllowedHeader("*");
       corsConfiguration.addAllowedMethod("*");
       corsConfiguration.setAllowCredentials(true);
       UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
       urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
       return new CorsFilter(urlBasedCorsConfigurationSource);
  }

}

Spring Cloud

為什么需要學習Spring Cloud

不論是商業應用還是用戶應用,在業務初期都很簡單,我們通常會把它實現為單體結構的應用。

但是,隨着業務逐漸發展,產品思想會變得越來越復雜,單體結構的應用也會越來越復雜。

這就會給應用帶來如下的幾個問題:

  • 代碼結構混亂:業務復雜,導致代碼量很大,管理會越來越困難。同時,這也會給業務的快速迭代帶來巨大挑戰;

  • 開發效率變低:開發人員同時開發一套代碼,很難避免代碼沖突。開發過程會伴隨着不斷解決沖突的過程,這會嚴重的影響開發效率;

  • 排查解決問題成本高:線上業務發現 bug,修復 bug 的過程可能很簡單。但是,由於只有一套代碼,需要重新編譯、打包、上線,成本很高。

由於單體結構的應用隨着系統復雜度的增高,會暴露出各種各樣的問題。近些年來,微服務架構逐漸取代了單體架構,且這種趨勢將會越來越流行。Spring Cloud是目前最常用的微服務開發框架,已經在企業級開發中大量的應用。

什么是Spring Cloud

Spring Cloud是一系列框架的有序集合

它利用Spring Boot的開發便利性巧妙地簡化了分布式系統基礎設施的開發,如服務發現注冊、配置中心、智能路由、消息總線、負載均衡、斷路器、數據監控等,都可以用Spring Boot的開發風格做到一鍵啟動和部署。

Spring Cloud並沒有重復制造輪子,它只是將各家公司開發的比較成熟、經得起實際考驗的服務框架組合起來,通過Spring Boot風格進行再封裝,屏蔽掉了復雜的配置和實現原理,最終給開發者留出了一套簡單易懂、易部署和易維護的分布式系統開發工具包。

設計目標:協調各個微服務,簡化分布式系統開發

Spring Cloud優缺點

微服務的框架那么多比如:dubbo、Kubernetes,為什么就要使用Spring Cloud的呢?

優點:

  • 產出於Spring大家族,Spring在企業級開發框架中無人能敵,來頭很大,可以保證后續的更新、完善

  • 組件豐富,功能齊全。Spring Cloud 為微服務架構提供了非常完整的支持。例如、配置管理、服務發現、斷路器、微服務網關等;

  • Spring Cloud 社區活躍度很高,教程很豐富,遇到問題很容易找到解決方案

  • 服務拆分粒度更細,耦合度比較低,有利於資源重復利用,有利於提高開發效率

  • 可以更精准的制定優化服務方案,提高系統的可維護性

  • 減輕團隊的成本,可以並行開發,不用關注其他人怎么開發,先關注自己的開發

  • 微服務可以是跨平台的,可以用任何一種語言開發

  • 適於互聯網時代,產品迭代周期更短

缺點:

  • 微服務過多,治理成本高,不利於系統維護

  • 分布式系統開發的成本高(容錯,分布式事務等),對團隊挑戰大

總的來說優點大過於缺點,目前看來Spring Cloud是一套非常完善的分布式框架,目前很多企業開始用微服務、Spring Cloud的優勢是顯而易見的。

因此對於想研究微服務架構的同學來說,學習Spring Cloud是一個不錯的選擇。

Spring Cloud整體架構

Spring Cloud主要項目有哪些

Spring Cloud的子項目,大致可分成兩類,一類是對現有成熟框架"Spring Boot化"的封裝和抽象,也是數量最多的項目;

第二類是開發了一部分分布式系統的基礎設施的實現,如Spring Cloud Stream扮演的就是kafka, ActiveMQ這樣的角色。

Spring Cloud Config

集中配置管理工具,分布式系統中統一的外部配置管理,默認使用Git來存儲配置,可以支持客戶端配置的刷新及加密、解密操作。

Spring Cloud Netflix

Netflix OSS 開源組件集成,包括Eureka、Hystrix、Ribbon、Feign、Zuul等核心組件。

  • Eureka:服務治理組件,包括服務端的注冊中心和客戶端的服務發現機制;

  • Ribbon:負載均衡的服務調用組件,具有多種負載均衡調用策略;

  • Hystrix:服務容錯組件,實現了斷路器模式,為依賴服務的出錯和延遲提供了容錯能力;

  • Feign:基於Ribbon和Hystrix的聲明式服務調用組件;

  • Zuul:API網關組件,對請求提供路由及過濾功能。

Spring Cloud Bus

用於傳播集群狀態變化的消息總線,使用輕量級消息代理連接分布式系統中的節點,可以用來動態刷新集群中的服務配置。

Spring Cloud Consul

基於Hashicorp Consul的服務治理組件。

Spring Cloud Security

安全工具包,對Zuul代理中的負載均衡OAuth2客戶端及登錄認證進行支持。

Spring Cloud Gateway

新一代API網關組件,對請求提供路由及過濾功能

Spring Cloud OpenFeign

基於Ribbon和Hystrix的聲明式服務調用組件,可以動態創建基於Spring MVC注解的接口實現用於服務調用,在Spring Cloud 2.0中已經取代Feign成為了一等公民。

SpringBoot和SpringCloud的區別?

SpringBoot專注於快速、方便的開發單個微服務個體,SpringCloud關注全局的服務治理框架。

SpringCloud將SpringBoot開發的一個個單體微服務整合並管理起來,為各個微服務之間提供配置管理、服務發現、斷路器、路由、微代理、事件總線、全局鎖、決策競選、分布式會話等等集成服務

SpringBoot可以離開SpringCloud獨立開發項目, 但是SpringCloud離不開SpringBoot ,屬於依賴的關系。

Dubbo 和 Spring Cloud 有什么關系?Dubbo 和 Spring Cloud 有什么哪些區別?

Dubbo 是 SOA 時代的產物,它的關注點主要在於服務的調用,流量分發、流量監控和熔斷。

Spring Cloud 誕生於微服務架構時代,考慮的是微服務治理的方方面面,另外由於依托了 Spring、Spring Boot 的優勢,兩個框架在目標就不一致,Dubbo 定位服務治理、Spring Cloud 是打造一個分布式的生態。

Dubbo 底層是使用 Netty 這樣的 NIO 框架,是基於 TCP 協議傳輸的,配合以 Hession 序列化完成 RPC 通信。

Spring Cloud 是基於 Http 協議,使用 Restful 風格進行接口通信,相對來說 Http 請求會有更大的報文,占的帶寬也會更多。

但是 Restful 相比 RPC 更為靈活,服務提供方和調用方的依賴只依靠一紙契約,不存在代碼級別的強依賴,這在強調快速演化的微服務環境下,顯得更為合適,至於注重通信速度還是方便靈活性,具體情況具體分析。

SOA和微服務的對比

微服務是一種和SOA相似但本質上不同的架構理念

  • 相似點在於兩者都關注“服務”,都是通過服務的拆分來解決可擴展性問題

  • 本質上不同的地方在於幾個核心理念的差異:是否有ESB(企業服務總線)、服務的粒度、架構設計的目標

SOA和微服務的對比

1、服務粒度
  • SOA的服務粒度要粗一些,而微服務要細一些

  • 例如,對一個大型企業來說,“員工管理系統”就是一個SOA架構中的服務;而如果采用微服務架構,則“員工管理系統”會被拆分為更多的服務,比如“員工信息管理”“員工考勤管理”“員工假期管理”和“員工福利管理”等更多服務

2、服務通信
  • SOA采用了ESB作為服務間通信的關鍵組件,負責服務定義、服務路由、消息轉換、消息傳遞,總體上是重量級的實現;微服務推薦使用統一的協議和格式,例如,RESTful協議、RPC協議,無須ESB這樣的重量級實現

3、服務交付
  • SOA對服務的交付並沒有特殊要求,因為SOA更多考慮的是兼容已有的系統;微服務的架構理念要求“快速交付”,相應地要求采取自動化測試、持續集成、自動化部署等敏捷開發相關的最佳實踐

4、應用場景
  • SOA更加適合於龐大、負責異構的企業級系統,這類系統都發展多年,采用不同的企業級技術,有的是內部開發的,有的是外部購買的,無法完全推倒重來或者進行大規模的優化和重構,由於成本和影響太大,只能采用兼容的方式進行處理,而承擔兼容任務的就是ESB

  • 微服務更加適合於快速、輕量級、基於Web的互聯網系統,這類系統業務變化快,需要快速嘗試、快速交付;雖然開發技術可能差異很大(Java、C++、.NET等),但對外接口基本都是提供HTTP RESTful風格的接口,無須考慮在接口層進行類似SOA的ESB處理

SOA和微服務對比如下

Nacos

什么是 Nacos

Nacos 致力於幫助您發現、配置和管理微服務Nacos 提供了一組簡單易用的特性集,幫助您快速實現動態服務發現、服務配置、服務元數據及流量管理。

Nacos 幫助您更敏捷和容易地構建、交付和管理微服務平台。Nacos 是構建以“服務”為中心的現代應用架構 (例如微服務范式、雲原生范式) 的服務基礎設施。

Nacos 的關鍵特性包括:

  • 服務發現和服務健康監測

    Nacos 支持基於 DNS 和基於 RPC 的服務發現。Nacos 提供對服務的實時的健康檢查,阻止向不健康的主機或服務實例發送請求。

  • 動態配置服務

    動態配置服務可以讓您以中心化、外部化和動態化的方式管理所有環境的應用配置和服務配置。

  • 動態 DNS 服務

    動態 DNS 服務支持權重路由,讓您更容易地實現中間層負載均衡、更靈活的路由策略、流量控制以及數據中心內網的簡單DNS解析服務。

  • 服務及其元數據管理

    Nacos 能讓您從微服務平台建設的視角管理數據中心的所有服務及元數據,包括管理服務的描述、生命周期、服務的靜態依賴分析、服務的健康狀態、服務的流量管理、路由及安全策略、服務的 SLA 以及最首要的 metrics 統計數據。

Nacos基本架構及概念

服務 (Service)

服務是指一個或一組軟件功能(例如特定信息的檢索或一組操作的執行),其目的是不同的客戶端可以為不同的目的重用(例如通過跨進程的網絡調用)。

Nacos 支持主流的服務生態,如 Kubernetes Service、gRPC|Dubbo RPC Service 或者 Spring Cloud RESTful Service.

服務注冊中心 (Service Registry)

服務注冊中心,它是服務,其實例及元數據的數據庫。服務實例在啟動時注冊到服務注冊表,並在關閉時注銷。

服務和路由器的客戶端查詢服務注冊表以查找服務的可用實例。服務注冊中心可能會調用服務實例的健康檢查 API 來驗證它是否能夠處理請求。

服務元數據 (Service Metadata)

服務元數據是指包括服務端點(endpoints)、服務標簽、服務版本號、服務實例權重、路由規則、安全策略等描述服務的數據

服務提供方 (Service Provider)

是指提供可復用和可調用服務的應用方

服務消費方 (Service Consumer)

是指會發起對某個服務調用的應用方

配置 (Configuration)

在系統開發過程中通常會將一些需要變更的參數、變量等從代碼中分離出來獨立管理,以獨立的配置文件的形式存在。目的是讓靜態的系統工件或者交付物(如 WAR,JAR 包等)更好地和實際的物理運行環境進行適配。配置管理一般包含在系統部署的過程中,由系統管理員或者運維人員完成這個步驟。配置變更是調整系統運行時的行為的有效手段之一。

配置管理 (Configuration Management)

在數據中心中,系統中所有配置的編輯、存儲、分發、變更管理、歷史版本管理、變更審計等所有與配置相關的活動統稱為配置管理。

名字服務 (Naming Service)

提供分布式系統中所有對象(Object)、實體(Entity)的“名字”到關聯的元數據之間的映射管理服務,例如 ServiceName -> Endpoints Info, Distributed Lock Name -> Lock Owner/Status Info, DNS Domain Name -> IP List, 服務發現和 DNS 就是名字服務的2大場景。

配置服務 (Configuration Service)

在服務或者應用運行過程中,提供動態配置或者元數據以及配置管理的服務提供者。

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM