【原創】SpringBoot 2.7.0通過lettuce及commons-pool2 v2.9.0整合Redis踩坑記錄

Candyメ奶糖 發表於 2022-06-12
Redis Spring

背景

公司的一個專案由於HTTPS證照到期,導致小程式、POS不能正常使用。所以百度了下,通過URL檢測證照有效期的程式碼,並自行整合到一個服務中。
程式碼倉庫:[基於SpringBoot + 企業微信 + 釘釘 的通知服務] (https://gitee.com/tec-cloud/tec-notice),由於碼雲的倉庫策略調整,可能無法正常訪問。

問題溯源

spring: 
  redis:
    client-type: lettuce
    host: 127.0.0.1
    lettuce:
      pool:
        #最大連線數
        max-active: 10
        #連線池中最小空閒連線
        min-idle: 2
        #連線池中最大空閒連線
        max-idle: 3
        #最大建立連線等待時間。如果超過此時間將接到異常。設為-1表示無限制。
        max-wait: 60s
        #空閒連結檢測執行緒檢測週期毫秒(負值表示不檢測)(型別為Duration,新增秒)
        time-between-eviction-runs: 60s
      #關閉超時時間
      shutdown-timeout: 1s
    port: 6379
    password:
    #連線超時時間毫秒(型別為Duration,新增秒)
    timeout: 60s

以上是redis的配置,想將配置儲存在redis中,所以通過lettuce整合spring-boot-starter-data-redis。

根據依賴傳遞spring-boot-starter-data-redis v2.7.0 --> lettuce-core v6.1.8.RELEASE --> commons-pool2 v2.9.0定位到依賴配置,如下:

    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-pool2</artifactId>
      <version>2.9.0</version>
      <scope>compile</scope>
      <optional>true</optional>
    </dependency>

同時,我注意到optional=true,所以在專案根pom.xml新增本依賴,並移除optional。如下:

    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-pool2</artifactId>
      <version>2.9.0</version>
      <scope>compile</scope>
    </dependency>

啟動後,報錯:

2022-06-12 16:32:17.716 ERROR 15092 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

    org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration$PoolBuilderFactory.getPoolConfig(LettuceConnectionConfiguration.java:185)

The following method did not exist:

    org.apache.commons.pool2.impl.GenericObjectPoolConfig.setTimeBetweenEvictionRuns(Ljava/time/Duration;)V

The calling method's class, org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration$PoolBuilderFactory, was loaded from the following location:

    jar:file:/C:/Users/Administrator/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.7.0/spring-boot-autoconfigure-2.7.0.jar!/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration$PoolBuilderFactory.class

The called method's class, org.apache.commons.pool2.impl.GenericObjectPoolConfig, is available from the following locations:

    jar:file:/C:/Users/Administrator/.m2/repository/org/apache/commons/commons-pool2/2.9.0/commons-pool2-2.9.0.jar!/org/apache/commons/pool2/impl/GenericObjectPoolConfig.class

The called method's class hierarchy was loaded from the following locations:

    org.apache.commons.pool2.impl.GenericObjectPoolConfig: file:/C:/Users/Administrator/.m2/repository/org/apache/commons/commons-pool2/2.9.0/commons-pool2-2.9.0.jar
    org.apache.commons.pool2.impl.BaseObjectPoolConfig: file:/C:/Users/Administrator/.m2/repository/org/apache/commons/commons-pool2/2.9.0/commons-pool2-2.9.0.jar
    org.apache.commons.pool2.BaseObject: file:/C:/Users/Administrator/.m2/repository/org/apache/commons/commons-pool2/2.9.0/commons-pool2-2.9.0.jar


Action:

Correct the classpath of your application so that it contains compatible versions of the classes org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration$PoolBuilderFactory and org.apache.commons.pool2.impl.GenericObjectPoolConfig

Disconnected from the target VM, address: '127.0.0.1:51044', transport: 'socket'

Process finished with exit code 1

根據日誌,確認錯誤:不存在GenericObjectPoolConfig.setTimeBetweenEvictionRuns方法,啟動發生錯誤,終止並退出。

本著週末不學習就是退步的想法,跟蹤了https://github.com/apache/commons-pool.githttps://github.com/spring-projects/spring-boot.git對應的版本、TAG及commit history。僅在spring-boot的提交記錄中發現一點端倪。
如圖:
【原創】SpringBoot 2.7.0通過lettuce及commons-pool2 v2.9.0整合Redis踩坑記錄
【原創】SpringBoot 2.7.0通過lettuce及commons-pool2 v2.9.0整合Redis踩坑記錄
不過提交時間是在spring-boot v2.7.x的初始化釋出日期2022-05-19之前,參考:https://spring.io/projects/spring-boot#support

最終只要帶著這個困惑,翻閱spring-boot、spring-data-redis的closed的Issue,結果被我搜個正著。
https://github.com/spring-projects/spring-data-redis/issues?q=is%3Aissue+is%3Aclosed+GenericObjectPoolConfig
根據其中的討論,得到有效資訊,依賴版本有衝突,刪掉了2.9.0:The problem solved by deleting explicit dependency org.apache.commons:commons-pool2:2.9.0. Now it uses commpons-pool2:2.11.1
見連結:
https://github.com/spring-projects/spring-data-redis/issues/2293#issuecomment-1084310766

馬不停蹄地開始試驗:

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

服務正常啟動了。

解決方案

版本由spring-boot-dependencies來控制,直接讀取<commons-pool2.version>2.11.1</commons-pool2.version>即可。當然也可以使用${commons-pool2.version}來明確定義版本。

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>