SpringCloud/SpringBoot升级拆坑

前言

在spring官方网站的主页里,赫赫醒目的标题写着“Spring makes Java simple.modern.productive.reactive.cloud-ready。”;(Spring使Java简单易用、紧跟时代、复用性强、快速响应、云就绪)

SpringCloud/SpringBoot升级拆坑_spring cloud

如spring所宣称的;springcloud/springboot就是使用java语言里实现和搭建微服务体系;最好的Java微服务技术框架、微服务项目开发框架以及微服务化的解决方案; 目前springcloud是依托springboot来实现整个微服务体系;每个springcloud的组件也都是依赖于springboot; springboot和springcloud版本如下

SpringCloud/SpringBoot升级拆坑_spring boot_02

笔者一直使用的2.3.x的版本

SpringCloud/SpringBoot升级拆坑_spring boot_03

今天要给拆的坑,就是笔者升级springboot从2.3.x到2.6.x,springcloud从hoxton升级到2021.0.x的过程中踩到的坑; 这个升级的过程是发生在2022年上半年,笔者升级的时候,springboot还没有出2.7.x的版本,最后的版本是springboot2.6.3; springcloud的版本使用的是2021.0.1; springcloud-alibaba在升级时,还没有出针对springcloud2021.0.1的版本,所以升级中,springcloud alibaba的版本没变,用的是2.2.7.RELEASE(现在springcloud alibaba已经发布了支持springcloud2021.0.1的版本2021.0.1);

升级后目标版本如下图pom.xml所示

SpringCloud/SpringBoot升级拆坑_spring boot_04

bootstrap配置文件不生效

项目启动后不能跑, datasource不能配置成功,debug也不能配置成功,推断是配置文件bootstrap没有加载的问题

原因:

SpringBoot本身并不支持,需要和Spring Cloud 的组件结合——只有加上Spring Cloud Context依赖才能生效。

拆坑:

需要加入

<!--引入springcloud上下文依赖,使bootstrap配置文件生效-->

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-bootstrap</artifactId>

</dependency>

Spring Boot 2.6.x整合Swagger启动失败报错问题解决(治标还治本)

Spring Boot 2.6.x版本引入依赖 springfox-boot-starter (Swagger 3.0) 后,启动容器会报错: Failed to start bean ‘ documentationPluginsBootstrapper ‘ ; nested exception…

原因:

Springfox 假设 Spring MVC 的路径匹配策略是 ant-path-matcher,而 Spring Boot 2.6.x版本的默认匹配策略是 path-pattern-matcher,这就造成了上面的报错。

拆坑:

方案一(治标)

在 application.properties 配置文件中修改mvc的匹配策略:

spring.mvc.pathmatch.matching-strategy=ant-path-matcher

注意:开始的时候我用这个方法的确可以正常启动了,但后来我发现此方法在某些服务启动时会失效!我查了一下才发现这个方法治标不治本,具体如下:

只有在不使用 Spring Boot 的执行器时,此功能才起作用。
无论配置的匹配策略如何,执行器将始终使用基于路径模式的解析 ( 也就是默认策略 ) 。
如果您想在 Spring Boot 2.6及更高版本中将其与执行器一起使用,则需要对 Springfox 进行更改。

方案二(治本)

这个办法是我在 github 上找到的,解决方案是将 Springfox 的某 .java 文件复制到自己项目里进行修改,后来有看到一个更好的解决方案,我觉得非常好,在这里分享一下:

在你的项目里添加这个 bean :(加在配置类里就可)

@Bean
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}

private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
List<T> copy = mappings.stream()
.filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}

@SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}

Spring2.6 Swagger Knife4j的集成

解决上面问题后,文档中心的接口列表没有了;

原因:

部分jar不相互的版本冲突;
各种配置,各种搭配试过来,

最终方案:

必须两者同时都修改

spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
@Configuration

@EnableKnife4j

@EnableSwagger2

@EnableConfigurationProperties(ApiDocConfigProperties.class)

public static class DocketConfiguration{

通过spring gateway访问其他服务503 service unavailable

原因:

Spring Cloud 2020.0.0版本之前会自动引入Netflix Ribbon依赖,Netflix Ribbon功能跟loadbalancer一样, 因Netflix公司停止维护Ribbon后, 在Spring Cloud 2020.0.0版本之后Spring使用loadbalancer替代了Ribbon, 但是loadbalancer依赖需要手动引入。

拆坑(解决方案):

引入loadbalancer

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

由上个升级LoadBalance引起的后续问题:

增加loadbalancer后启动提示:Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath
拆坑(解决方案):

解决方案是引入caffeine,或者关闭cache

<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.0.5</version>
</dependency>

启动的问题解决了,访问其他服务时提示:LoadBalancerCacheManager not available, returning delegate without caching

拆坑(解决方案):

修改配置:

spring:
cloud:
loadbalancer:
ribbon:
enabled: false
cache:
enabled: true
caffeine:
spec: initialCapacity=500,expireAfterWrite=5s

但是发现配置有可能还会存在提示,没有生效!网络上有说Naocs discovery依赖有冲突导致没生效,exclusion spring-cloud-starter-netflix-ribbon,但是实际查看了下此版本并没有依赖这个包,所以还需确认。

MySQL JDBC Driver错误

启动出现错误:Loading class ‘com.mysql.jdbc.Driver’. This is deprecated. The new driver class is ‘com.mysql.cj.jdbc.Driver’. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

原因

项目中使用到了log4jdbc-log4j2-jdbc4.1,升级后出现此错误提示。 因为mysql最新驱动名称为com.mysql.cj.jdbc.Driver,log4jdbc只支持com.mysql.jdbc.Driver,所以需要将自动加载数据库驱动关闭。

拆坑(解决方案):

resources文件下新增log4jdbc.log4j2.properties文件

log4jdbc.auto.load.popular.drivers=false

log4jdbc.drivers=com.mysql.cj.jdbc.Driver

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

Process finished with exit code 1

测试启动过程中,发现Idea直接退出,没有任何提示输出。

原因:

Idea的设置问题导致

拆坑(解决方案):

在启动的Edit Configuration里设置指定服务的Active profiles,例如:local

Dubbo引入报错

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.

java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@f0da945 has not been refreshed yet

原因:

javax/ws/rs/Path 是属于jsr311-api.jar 包下的,引入相关jsr311-api包即可。

拆坑(解决方案):

引入相关包

<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>

升级后没有引入javax.validation包

原因:

新版本中Spring Boot不自动包含validation包

拆坑(解决方案):

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-validation</artifactId>

</dependency>

RestTemplate通过nacos服务名访问报错

访问是报错java.net.UnknownHostException

原因:

此处还是因为2020版本不再使用netflix,没有了ribbon导致的问题,依旧是引入loadbalance代替rbibon:

拆坑(解决方案):

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-loadbalancer</artifactId>

</dependency>

持续报错

如果出现错误

An attempt was made to call a method that does not exist. The attempt was made from the following location: org.hibernate.validator.internal.xml.config.ValidationBootstrapParameters.<init>(ValidationBootstrapParameters.java:65) The following method did not exist: javax.validation.BootstrapConfiguration.getClockProviderClassName()Ljava/lang/String;

拆坑(解决方案):

升级JAVAEE至少8.0

<dependency>

<groupId>javax</groupId>

<artifactId>javaee-api</artifactId>

<version>8.0.1</version>

</dependency>

Nacos-discovery 升级至2.2.7.RELEASE;启动Nacos Client注册到Nacos2.0.4版本Server时, 注册失败

原因:

升级后的Nacos Client会连接9848的端口,来进行健康监控;旧版本Nacos Client不会有这个检查动作

拆坑(解决方案):

修改防火墙策略,打开Nacos Server的9848端口,允许内网访问Nacos Server的9848端口

通过fegin调用,出现报错

升级Nacos-Discovery后,所有的feign调用都会报错;如下

org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.AbstractMethodError: org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.choose(Ljava/lang/String;Lorg/springframework/cloud/client/loadbalancer/Request;)Lorg/springframework/cloud/client/ServiceInstance;
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1082)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)

原因:

包的依赖关系,在最上面我就说过了,我升级的时候SpringCloud Alibaba只是从2.2.6升级到了2.2.7还是不支持springcloud的2021.0.1版本; 所以包依赖出现冲突;

SpringCloud2021.0.1版本已经去除了对netfix-ribbon的依赖, 使用loadbalance代替,但是对于spring-cloud-starter-alibaba-nacos-discovery2.2.7版本并没有对此进行处理,还是使用netfix-ribbon

拆坑(解决方案):

去除掉对netfix-ribbon的依赖

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>

SpringCloud/SpringBoot升级拆坑_spring_05