天天看點

Spring Boot 2.4.0正式釋出,全新的配置檔案加載機制(不向下相容)✍前言✍正文✍總結

千裡之行,始于足下。關注公衆号【BAT的烏托邦】,有Spring技術棧、MyBatis、JVM、中間件等小而美的原創專欄供以免費學習。分享、成長,拒絕淺嘗辄止。本文已被 https://www.yourbatman.cn 收錄。
Spring Boot 2.4.0正式釋出,全新的配置檔案加載機制(不向下相容)✍前言✍正文✍總結

✍前言

你好,我是YourBatman。

中原標準時間2020-11-12,

Spring Boot 2.4.0

正式釋出。2.4.0是第一個使用新版本方案的Spring Boot發行版本。

注意:2.4.0版本号沒有

.RELEASE

字尾,沒有

.RELEASE

.RELEASE

字尾。使用的是Spring最新的版本釋出規則。此規則詳解請參考上篇文章: Spring改變版本号命名規則:此舉對非英語國家很友好

還記得

Spring Boot 2.3.0.RELEASE

版本釋出時那會麽?前後相差将好半年:

Spring Boot 2.4.0正式釋出,全新的配置檔案加載機制(不向下相容)✍前言✍正文✍總結

直達電梯:

Spring Boot 2.3.0正式釋出:優雅停機、配置檔案位置通配符新特性一覽

一般來說,次版本号的更新會有點料,根據之前的爆料此次更新據說是做了大量的更新和改進。那麼老規矩,作為小白鼠的我先代你玩一玩,初體驗吧。

也可參見官方的更新日志: Spring Boot 2.4.0 Release Notes

✍正文

除了剛釋出的Spring Boot 2.4.0,Spring Boot 2.3.x/2.2.x仍舊是活躍的維護的版本。Spring Boot遵循的是

Pivotal OSS

支援政策,從釋出日期起支援主要版本3年(注意:是主要版本)。下面是詳情:

  • 2.3.x

    :支援的版本。2020.05釋出,是現在的活躍的主幹
  • 2.2.x

    :支援的版本。2019.10釋出,是現在的活躍的主幹
  • 2.1.x

    :2018.10釋出,支援到2020.10月底,建議盡快更新

EOL分支:

  • 2.0.x

    :2018.3釋出,2019.4.3停止維護
  • 1.5.x

    :生命已終止的版本。2017.1釋出,是最後一個1.x分支,2019.8.1停止維護
Spring Boot 2.4.0正式釋出,全新的配置檔案加載機制(不向下相容)✍前言✍正文✍總結

回憶2.3版本的新特性

可能大部分小夥伴都還沒用過2.3.x分支,沒想到2.4.x就已釋出。是以這裡先對2.3.x版本的新特性,來波簡單回憶:

  1. 優雅停機。這是2.3.x主打的新特性:在關閉時,web伺服器将不再允許新的請求,并将等待完成的請求給個寬限期讓它完成。這個寬限期是可以設定的:可以使用

    spring.lifecycle.timeout-per-shutdown-phase=xxx

    來配置,預設值是30s。
  2. 配置檔案位置支援通配符。簡單的說,如果你有MySql的配置和Redis配置的話,你就可以把他們分開來放置,這個新特性也是棒棒哒。隔離性更好目錄也更加清晰了(注意:此格式隻支援放在classpath外部):
    1. mysql:

      /config/mysql/application.properties

    2. redis:

      /config/redis/application.properties

  3. 核心依賴更新。
    1. Spring Data Neumann。備注:很明顯這個還是舊的命名方式。在Spirng新的版本規則下,Spring Data最新版本為Spring Data 2020.0.0
    2. Spring Session Dragonfruit(很明顯這個也還是舊的命名方式)
    3. Spring Security 5.3
    4. Spring Framework 沒有更新,使用的依舊是和Spring Boot 2.2相同的

      5.2.x

      版本
      1. 說明:小版本号的更新對于新特性來說一般選擇性忽略
    5. 關于Bean Validation:從此版本開始,

      spring-boot-starter-web

      不會再把validation帶進來,是以若使用到,你需要自己添加這個

      spring-boot-starter-validation

      依賴
      1. 一般來說建議你手動引入,畢竟Bean Validation的使用還是很廣泛,并且真的非常非常好用

做足功課後,就開始最新的Spring Boot 2.4.0之旅吧。

2.4.0主要新特性

全新的配置檔案處理(properties/yaml)

這個改變最為重磅,本次改變了配置檔案的加載邏輯,旨在簡化和合理化外部配置的加載方式,它可能具有不向下相容性。

Spring Boot 2.4改變了處理

application.properties

application.yml

檔案的方式:

  • 若你隻是簡單的檔案application.properties/yaml,那麼更新對你是無縫的,你感受不到任何變化
  • 若你使用了比較複雜的檔案,如

    application-profile.properties/yaml

    這種(或者使用了Spirng Cloud的配置中心、(帶有分隔符----的)多yaml檔案),那麼預設是不向下相容的,需要你顯式的做出些更改

因為配置檔案隸屬于程式的一部分,特别是我們現在幾乎都會使用到配置中心。是以下面針對于老版本更新到Spring Boot 2.4.0做個簡單的遷移指導。

說明:因配置檔案加載邏輯完全進行了重寫,是以詳細版本我放到了下文專文講解,有興趣可保持關注

老版本版本配置屬性遷移指南

老版本:2.4.0之前的版本都叫老版本。

Spring Boot 2.4對

application.poperties/yaml

的處理做了更新/更新。旨在簡化和合理化外部配置的加載方式。它還提供了新功能:

spring.config.import

支援。是以呢,對于Spring Boot 2.4.0之前的版本(老版本)若更新到2.4.0需要做些修改,指導建議如下:

方式一:恢複舊模式(不推薦)

如果你還未準備好做配置遷移的修改,Spring Boot也幫你考慮到了,提供了一鍵切換到舊模式的“按鈕”。具體做法是:隻需要在

Environment

裡增加一個屬性

spring.config.use-legacy-processing = true

就搞定。最簡的方式就是把這個屬性放在application.poperties/yaml裡即可。

spring.config.use-legacy-processing = true           

增加此配置後,Spring Boot對配置檔案的解析恢複到原來模式:仍舊使用

ConfigFileApplicationListener

去解析。

ConfigFileApplicationListener

屬于Spring Boot非常核心的底層代碼,這次做了不向下相容的改進,可見它對進擊雲原生的決心

值得注意的是:此API在2.4.0已被标記為過期:

// @since 1.0.0
// @deprecated since 2.4.0 in favor of {@link ConfigDataEnvironmentPostProcessor}
@Deprecated
public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
    ...
}           

按照Spring Boot的版本政策,此類将在Spring Boot 2.6.0版本被移除。是以:若不是迫不得已(時間緊急),并不建議你用相容手法這麼去做,因為這将成為技術債,遲早要還的。

說明:很多RD其實隻會看到目前的友善,獲得利益(比如快速上線獲獎),坑交給後人。我個人認為作為程式員應該有一定自我修養,自我追求,不為一時的爽而持續給團隊積累債務,畢竟積重難返。
方式二:按新規則遷移(推薦)

若你對配置檔案的使用有如下情行,那麼你需要做遷移:

  1. 多文檔的yaml檔案(帶有----分隔符的檔案)
  2. 在Jar外使用配置檔案,或者使用形如application-{xxx}.properties/yaml這種配置
  3. 若在多文檔yaml中使用到了

    spring.profiles

    配置項
  4. ...

Spring Boot 2.4.0更新對配置檔案的改動是最大的,并且還不具備向下相容性,簡單的說就是從此版本開始要把Spring Boot的配置檔案加載機制重學一遍(比如還增加了

spring.config.import

,增加了對kubernetes配置的支援等等),并且還要學會如何遷移。

為了更好的描述好這個非常非常重要的知識點,下篇文章我會用專文來全面介紹 Spring Boot這套全新的配置檔案加載機制,并且輔以原理,以及和過去方式的比較,幫助你更全面、更快速、更勞的掌握它,歡迎持續關注。

說明:Spring Boot的配置檔案加載機制非常非常重要,因為你也知道你平時開發中很大程度實際上是在跟它的配置項打交道。新的配置加載方式比老的更加優秀,适應發展,敬請期待

從spring-boot-starter-test中删除Vintage Engine

Spring Boot 2.2.0

版本開始就引入JUnit 5作為單元測試預設庫,在此之前,spring-boot-starter-test包含的是JUnit 4的依賴,Spring Boot 2.2.0版本之後替換成了Junit Jupiter(Junit5)。

Vintage Engine屬于Junit5的一個子產品,它的作用是:允許用JUnit 5運作用JUnit 4編寫的測試,進而提供了向下相容的能力。

從2.2.0到現在經過了2個版本的疊代,到

Spring Boot 2.4.0

這個版本決定了把Vintage Engine從spring-boot-starter-test正式移除。是以:若你的工程仍需要對JUnit4支援,那麼請手動引入依賴項(如果工程量不大,強烈建議使用JUnit5,比4好用太多):

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>           
說明:其實在2.4.0之前,若你是從

https://start.spring.io

生成的項目其實也是不會帶有vintage-engine的。隻不過它是通過顯式的在pom裡通過exclusion标簽來排除的

嵌入式資料庫檢測

改進嵌入式資料庫檢測機制:僅當資料庫在記憶體中時才将其視為嵌入式資料庫。是以如果使用H2、HSQL等産品,但是你是基于檔案的持久性或使用的是伺服器模式,那麼将不會檢測為記憶體資料庫。而對于非記憶體資料庫,你可能需要額外做如下動作:

  1. sa使用者名将不會再被主動設定。是以如果你的資料庫需要使用者名,請增加配置項:

    spring.datasource.username = sa

  2. 這種資料庫将不會再被自動初始化,若要使用請根據需要更改

    spring.datasource.initialization-mode

    的值

Logback配置屬性

Logback一些配置項改名了,更加表名了它是logback的配置項。

新增了配置類

LogbackLoggingSystemProperties

用于對應,它繼承自之前的

LoggingSystemProperties

之前的配置項有些被廢棄(此版本還未删除,後續版本肯定會删除的),對應關系如下:

老(已廢棄)
logging.pattern.rolling-file-name logging.logback.rollingpolicy.file-name-pattern
logging.file.clean-history-on-start logging.logback.rollingpolicy.clean-history-on-start
logging.file.max-size logging.logback.rollingpolicy.max-file-size
logging.file.total-size-cap logging.logback.rollingpolicy.total-size-cap
logging.file.max-history logging.logback.rollingpolicy.max-history

一些屬性是被放到system environment裡面的:

ROLLING_FILE_NAME_PATTERN LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN
LOG_FILE_CLEAN_HISTORY_ON_START LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START
LOG_FILE_MAX_SIZE LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE
LOG_FILE_TOTAL_SIZE_CAP LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP
LOG_FILE_MAX_HISTORY LOGBACK_ROLLINGPOLICY_MAX_HISTORY

不再注冊DefaultServlet

從Spring Boot 2.4開始,預設将不會再注冊

DefaultServlet

。因為在絕大多數的應用中,Spring MVC提供的

DispatcherServlet

是唯一需要被注冊的Servlet。從源碼處感受下這次改動:

AbstractServletWebServerFactory:

// 2.4.0之前版本,預設值是true
private boolean registerDefaultServlet = true;
// 2.4.0以及之後版本,預設值是false
private boolean registerDefaultServlet = false;           

當然喽,若你的工程強依賴于此Servelt,那麼可以通過此配置項

server.servlet.register-default-servlet = true

把它注冊上去。

補課:什麼是DefaultServlet?

它是Java EE提供的标準技術,如Tomcat、Jetty等都提供了這個類。簡而言之它的作用就是兜底(攔截

/

),當别的servlet都沒比對上時就交給它來處理,一般用于處理靜态資源如

.jpg,.html,.js

這類的靜态檔案。

DefaultServlet

在傳統web容器裡,會被配置在tomcat目錄(此處以tomcat為例)下的

conf/web.xml

裡:

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
    </init-param>
    <init-param>
        <param-name>listings</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>           
說明:tomcat下的web.xml對其加載的所有的Application都生效,并且最終和Application自己的web.xml内容合并,遇相同的話後者優先級更高

在Spring Boot 嵌入式容器裡配置是這樣的(完全等價于xml配置):

private void addDefaultServlet(Context context) {
    Wrapper defaultServlet = context.createWrapper();
    defaultServlet.setName("default");
    defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet");
    defaultServlet.addInitParameter("debug", "0");
    defaultServlet.addInitParameter("listings", "false");
    defaultServlet.setLoadOnStartup(1);
    // Otherwise the default location of a Spring DispatcherServlet cannot be set
    defaultServlet.setOverridable(true);
    context.addChild(defaultServlet);
    context.addServletMappingDecoded("/", "default");
}           

值得注意的是:Spring Boot注冊的

DispatcherServlet

的path也是

/

(覆寫掉了

DefaultServelt

)。在Spring MVC環境下倘若是靜态資源,也不用DefaultServelt費心,Spring MVC專門提供了一個

DefaultServletHttpRequestHandler

用于處理靜态資源(雖然最終還是Dispatcher給

defaultServlet

去搞定)。

現在的Spring Boot服務大都是REST服務,并無靜态資源需要提供,是以就沒有必要啟用

DefaultServletHttpRequestHandler

和注冊

DefaultServlet

來增加不必要的開銷喽。

HTTP traces不再包含cookie頭

Http traces預設将不再包含請求頭

Cookie

以及響應頭

Set-Cookie

。源碼處感受一下:

org.springframework.boot.actuate.trace.http.Include:

// 2.4.0版本之前:包含COOKIE_HEADERS這個頭
static {
    Set<Include> defaultIncludes = new LinkedHashSet<>();
    defaultIncludes.add(Include.REQUEST_HEADERS);
    defaultIncludes.add(Include.RESPONSE_HEADERS);
    defaultIncludes.add(Include.COOKIE_HEADERS);
    defaultIncludes.add(Include.TIME_TAKEN);
    DEFAULT_INCLUDES = Collections.unmodifiableSet(defaultIncludes);
}
// 2.4.0版本以及之後:不包含COOKIE_HEADERS這個頭
static {
    Set<Include> defaultIncludes = new LinkedHashSet<>();
    defaultIncludes.add(Include.REQUEST_HEADERS);
    defaultIncludes.add(Include.RESPONSE_HEADERS);
    defaultIncludes.add(Include.TIME_TAKEN);
    DEFAULT_INCLUDES = Collections.unmodifiableSet(defaultIncludes);
}           

若你仍舊想保留老的習慣,那麼請用配置項

management.trace.http.include = cookies, errors, request-headers, response-headers

自行控制。

Neo4j

這個版本對Neo4j的支援進行了重大調整。直接用源碼來說明差異:

Spring Boot 2.4.0之前版本:

@ConfigurationProperties(prefix = "spring.data.neo4j")
public class Neo4jProperties implements ApplicationContextAware { ... }
// 無Neo4jDataProperties配置類           

Spring Boot 2.4.0以及之後版本:

@ConfigurationProperties(prefix = "spring.neo4j")
public class Neo4jProperties { ... }
@ConfigurationProperties(prefix = "spring.data.neo4j")
public class Neo4jDataProperties { ... }           

其它更新關注點

  • Spring Framework 5.3:Spring Boot 2.4.0使用的是5.3.0主線分支(之前使用的5.2.x或更低)
  • Spring Data 2020.0:Spring Boot 2.4.0使用的是最新釋出的Spring Data 2020.0
    • 此版本的命名方式不同于之前,是因為使用了Spirng最新的release train命名方式。Spring在2020年4月份釋出了最新的版本命名方式,可參考前面這篇文章:
  • 支援Java 15:此版本的Spring Boot完全支援Java 15,最小支援依舊是Java 8
  • 自定義屬性名支援:當使用構造函數綁定時,屬性的名稱需要和參數名稱保持一樣。如果您想使用Java保留關鍵字,這可能是一個問題。如下例子:
@ConfigurationProperties(prefix = "sample")
public class SampleConfigurationProperties {

  private final String importValue;

  // import是Java關鍵字
  public SampleConfigurationProperties(@Name("import") String importValue) {
    this.importValue = importValue;
  }

}           
@Name注解是Spring Boot 2.4.0新增的注解,能标注在

ElementType.PARAMETER

  • 支援導入無擴充名的配置檔案:如果您有這樣的需求,現在就可以通過向Spring Boot引導提供關于内容類型的提示來導入這些檔案
    • 此版本對Spring Boot的配置檔案加載進行了完全重新改造,并且不向下相容,具體參見下篇文章
  • 新增StartupEndpoint:顯示有關應用程式啟動的資訊。此端點可以幫助您識别啟動時間超過預期的bean
    • 此端點依賴于Spring Framework 5.3.0新提供的應用啟動追蹤新特性。具體可參考

      ApplicationStartup

      StartupStep

      這個兩個API是如何做追蹤的
  • 新增RedisCacheMetrics:用于監控使用redis時的puts、gets、deletes以及緩存命中率等資訊
    • 此名額資訊預設不開啟,需你增加配置

      spring.cache.redis.enable-statistics = true

  • 新增些Web配置項:

    spring.web.locale、spring.web.locale-resolver、spring.web.resources.*、management.server.base-path

    ,這些屬性既支援Servlet也支援WebFlux
    • 對應的隻能用于 Spring MVC或servelt下配置項

      spring.mvc.locale/spring.mvc.locale-resolver/spring.resources.*/management.server.servlet.context-path

      均以标注為過期
  • 支援Flyway 7:這個版本更新到Flyway 7,帶來了一些額外的屬性。如:

    spring.flyway.url/user/password

    (開源版本);

    spring.flyway.cherry-pick/jdbc-properties...

    (團隊版本)
  • H2資料庫控制台支援配置密碼:可通過

    spring.h2.console.settings.web-admin-password

    屬性配置通過密碼通路H2控制台
  • 增強的錯誤分析器FailureAnalizers:現在即使你還沒有建立ApplicationContext,FailureAnalizers都會生效來幫你定位錯誤位置
  • 處理/标注Spring Boot 2.2和2.3中過期項:按照Spring Boot的版本相容性政策,在2.2版本已被标記為

    @Deprecated

    的在2.4.0版本會被删除,在2.3版本中被标記為

    @Deprecated

    的計劃在2.5.0版本中将其移除

✍總結

這是A哥奉給大家的,對Spring Boot2.4.0版本新特性的介紹,希望對你有些幫助。

Spring Boot 2.4.0版本的更新目标,基本和Spring Framework 5.3.0保持一緻:為雲原生做努力。表現在除了删除些無用類,禁止不需要的類的加載外,重點還會展現在它對配置檔案加載機制的重構上,這将是下文的内容,也是本次更新的重頭戲,敬請關注。

Spring Boot重寫了對配置檔案的加載機制,并且新引入了近40個類來處理(老方式僅有區區幾個類),可見其重視、重要程度。是以,為了适應未來的發展,你一定要掌握,并且越早越好,下篇将為你揭曉。

✔推薦閱讀: