我服了!SpringBoot升級後這服務我一個星期都沒跑起來!(下)

2022-11-22 21:01:14

上一次的升級過程中差不多已經跑起來90%了,這週一上班解決完一點小問題,服務已經正常跑起來了,於是再拿著一些其他的服務測試了一下,又發現了一些其他的報錯,所以繼續。

14. DiscoveryEnabledServer Not Found

主要問題還是 eureka 中沒有了 ribbon 相關的依賴。

Caused by: java.lang.NoClassDefFoundError: com/netflix/niws/loadbalancer/DiscoveryEnabledServer
	at java.lang.Class.getDeclaredMethods0(Native Method) ~[?:?]
	at java.lang.Class.privateGetDeclaredMethods(Class.java:3167) ~[?:?]
	at java.lang.Class.getDeclaredMethods(Class.java:2310) ~[?:?]
	at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:467) ~[spring-core-5.3.23.jar:5.3.23]
	at org.springframework.util.ReflectionUtils.doWithLocalMethods(ReflectionUtils.java:321) ~[spring-core-5.3.23.jar:5.3.23]

解決方案:手動引入相關依賴包。

<dependency>
  <groupId>com.netflix.ribbon</groupId>
  <artifactId>ribbon-loadbalancer</artifactId>
  <version>2.7.18</version>
</dependency>
<dependency>
  <groupId>com.netflix.ribbon</groupId>
  <artifactId>ribbon-eureka</artifactId>
  <version>2.7.18</version>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
  <version>2.2.10.RELEASE</version>
</dependency>

15. 中介軟體迴圈依賴

依然是迴圈依賴報錯,之前沒注意看程式碼,簡單的設定了一下為延遲初始化,仔細一看發現程式碼這樣寫的,你細品。

然後啟動報錯:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cachesEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.class]: Unsatisfied dependency expressed through method 'cachesEndpoint' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: 
Requested bean is currently in creation: Is there an unresolvable circular reference?

16. CacheMetricsRegistrarConfiguration 報錯

由於在解決 15 的問題一開始是設定為延遲初始化,然後啟動發現仍然報錯。

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsRegistrarConfiguration': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsRegistrarConfiguration]: Constructor threw exception; nested exception is java.lang.StackOverflowError

解決方案:去掉 Autowired 注入,15和16的問題全部解決。

17. kafka-clients 版本和 spring-kafka 不相容

升級後預設spring-kafka是2.8.10版本,KafkaTemplate 報錯找不到類,原因在於本地kafka-clients使用的是 2.3.0 版本。

Caused by: java.lang.IllegalStateException: Failed to introspect Class [org.springframework.kafka.core.KafkaTemplate] from ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader@9e89d68]
Caused by: java.lang.NoClassDefFoundError: org/apache/kafka/clients/consumer/ConsumerGroupMetadata

解決方案:kafka-clients升級到相容版本 3.0.2 ,這個版本是 spring-cloud-dependency 中依賴的版本。

18. swagger啟動報錯

這個報錯是因為新版本 Spring Boot 將 Spring MVC 預設路徑匹配策略由AntPathMatcher改成了PathPatternParser,這個報錯在我這裡是WARN,而且非常隱蔽,需要仔細查詢。

[WARN] [2022.11.08 16:17:39.963] [10.135.0.95] [] [main] [org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext()] - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException

解決方案:設定成原來的AntPathMatcher,新增設定spring.mvc.pathmatch.matching-strategy= ANT_PATH_MATCHER

這個報錯資訊是一行 WARN 紀錄檔,非常難找,另外原因是根據網上資訊搜尋定位到的,這個報錯資訊我真的服了。

19. spring-session依賴報錯

啟動報錯資訊:

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

    org.springframework.boot.autoconfigure.session.SessionAutoConfiguration$ServletSessionConfiguration.cookieSerializer(SessionAutoConfiguration.java:109)

The following method did not exist:

    'void org.springframework.session.web.http.DefaultCookieSerializer.setSameSite(java.lang.String)'

The calling method's class, org.springframework.boot.autoconfigure.session.SessionAutoConfiguration$ServletSessionConfiguration, was loaded from the following location:

    jar:file:/Users/user/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.7.5/spring-boot-autoconfigure-2.7.5.jar!/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration$ServletSessionConfiguration.class

The called method's class, org.springframework.session.web.http.DefaultCookieSerializer, is available from the following locations:

    jar:file:/Users/user/.m2/repository/org/springframework/session/spring-session/1.3.5.RELEASE/spring-session-1.3.5.RELEASE.jar!/org/springframework/session/web/http/DefaultCookieSerializer.class

spring-session使用的是1.3.5.RELEASE,但是開啟 Maven 倉庫一看,這居然是最新版本?而且還是 2019 年的版本?

其實並非如此,查詢 Github 程式碼後發現是程式碼做了模組化拆分,新版本應該引入spring-session-core

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-core</artifactId>
    <version>2.7.0</version>
</dependency>

20. spring-security版本相容問題

在看到 SessionAutoConfiguration裡面程式碼同時發現spring-security相關依賴程式碼發生了改變。

解決方案:引入最新版本spring-security-web

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-web</artifactId>
  <version>5.7.4</version>
</dependency>

21. RibbonLoadBalancerClient啟動報錯

報錯資訊:

org.springframework.retry.RetryException: Could not recover; nested exception is java.lang.AbstractMethodError: Receiver class org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient does not define or inherit an implementation of the resolved method abstract choose(Ljava/lang/String;Lorg/springframework/cloud/client/loadbalancer/Request;)Lorg/springframework/cloud/client/ServiceInstance; of interface org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser.

原因在於位於spring-cloud-commons裡面的ServiceInstanceChooser#choose方法發生了改變。

而我們由於為了繼續使用spring-cloud-netflix-ribbon包,引入的只能是更新到2021年的最新版本2.2.10.RELEASE,這個包最後更新時間是 2021年11月份,所以這裡面實現的仍然是老的choose方法。

解決方案:使用同 package 名方式自己重寫該類,choose 方法的邏輯其實是和原來傳參 object 方法一樣的,或者自己把包拉下來改程式碼重新打包。

22. MongoDB報錯

spring-boot-autoconfigure新版本下MongoClientFactory建構函式發生改變,以前的寫法發生編譯錯誤。

以前的這種寫法傳參是MongoProperties

return new MongoClientFactory(mongoProperties).createMongoClient(mongoClientOptions());

現在的寫法:

MongoClientSettingsBuilderCustomizer customizer = new MongoPropertiesClientSettingsBuilderCustomizer(mongoProperties, environment);
return new MongoClientFactory(Lists.newArrayList(customizer)).createMongoClient(mongoClientOptions());

另外一個問題是原來的createMongoClient傳參是 MongoClientOptions,現在是 MongoClientSettings。

原來使用heartbeatFrequencyheartbeatConnectTimeout等等一些寫法也不一樣了,示意一下現在的寫法:

MongoClientSettings.builder()
  .applyToServerSettings(builder -> builder.heartbeatFrequency(8000, TimeUnit.MILLISECONDS))
  .applyToConnectionPoolSettings(builder -> builder.maxConnectionIdleTime(30000,TimeUnit.MILLISECONDS))
  .applyToSocketSettings(builder -> builder.connectTimeout(30000,TimeUnit.MILLISECONDS))
  .build();

另外,如果使用到了 morphia 的話,這個改動就更大了,基本老程式碼沒法用了,嘗試了一下,改不動,暫時放棄了。

總結

事情基本到這裡就暫時告一段落了,有一些老的程式碼改動太大,基本要廢棄重寫了,暫時擱置吧。