前言
前段时间,因项目被扫出大量漏洞,全是因为依赖版本过低,存在高中危漏洞需要升级。正好本来也有规划集群升级,因为工作量大迟迟落实不了,正好有这次修漏洞的机会,升级微服务集群。这篇文章主要记录了本人的升级记录,遇到的问题解决方法,仅供参考。
项目背景
项目微服务技术栈:Spring Boot 1.5.x 、Spring Cloud、Kafka、RabbitMq、Mysql、Eureka、Apollo、Nacos。Spring Boot 是1.5.x 版本非常老旧,Spring Cloud 版本也早就停更。根据Nacos的兼容情况,Spring Boot 的版本为2.6.13,但目前最新版是2.7.18,由于3.x跟2.x区别较大,因此决定使用2.7.18试试,Spring Cloud 版本为2021.0.5.0。
升级记录
在xml中加入依赖,过期的配置会提示:
代码语言:javascript复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
1、Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class is
com.mysql.cj.jdbc.Driver’
- 需要更新Mysql驱动
2、Caused by: java.lang.IllegalStateException: Could not resolve element type of Iterable type @。。。。。web.bind.annotation.RequestParam java.util.List. Not declared?
@RequestParam(value = "Long[]") List projectIds
此类的代码不能再使用
3、spring.rabbitmq.publisher-confirms 过期
4、Canonical names should be kebab-case (‘-’ separated)
- 不能使用驼峰形式,用
-
隔开
5、import org.springframework.cloud.netflix.feign
修改为 import org.springframework.cloud.openfeign
6、2.6以后不允许循环依赖
代码语言:javascript复制spring:
main:
# Spring Boot 2.6以后 默认不允许循环依赖
allow-circular-references: true
#允许bean覆盖
allow-bean-definition-overriding: true
7、spring.cloud.client.ipAddress 都修改为 spring.cloud.client.ip-address
8、跨域头修改
由原来的修改为
代码语言:javascript复制corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOriginPattern("*");
9、gateway 升级要注意去掉重复跨域头
spring.cloud.gateway.default-filters[0] = DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_FIRST
10、database配置过期
代码语言:javascript复制The use of configuration keys that have been renamed was found in the environment:
Property source 'ApolloBootstrapPropertySources':
Key: spring.datasource.data
Replacement: spring.sql.init.data-locations
Key: spring.datasource.platform
Replacement: spring.sql.init.platform
Key: spring.datasource.schema
Replacement: spring.sql.init.schema-locations
修改:
代码语言:javascript复制 sql:
init:
platform: mysql
#执行的sql语句
data-locations: classpath:data.sql
#执行的建表语句
schema-locations: classpath:schema.sql
11、Eureka 配置的修改
代码语言:javascript复制instance-id: ${spring.cloud.client.ip-address}:${server.port}
metadata-map:
user-name: ${spring.security.user.name}
user-password: ${spring.security.user.password}
12、上传配置的修改
代码语言:javascript复制spring:
servlet:
#最大上传大小,MB
multipart:
max-file-size: 1000MB
max-request-size: 1000MB
13、原有zuul适配
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.choose(Ljava/lang/String;Lorg/springframework/cloud/client/loadbalancer/Request;)Lorg/springframework/cloud/client/ServiceInstance
增加如下Bean
代码语言:javascript复制@Bean
public LoadBalancerClient blockingLoadBalancerClient(LoadBalancerClientFactory loadBalancerClientFactory) {
return new BlockingLoadBalancerClient(loadBalancerClientFactory);
}
14、调用接口报NoSuchMethodError: org.springframework.boot.web.servlet.error.ErrorController.getErrorPath
增加如下类
代码语言:javascript复制@Configuration
public class ZuulConfiguration {
/**
* The path returned by ErrorController.getErrorPath() with Spring Boot < 2.5
* (and no longer available on Spring Boot >= 2.5).
*/
private static final String ERROR_PATH = "/error";
private static final String METHOD = "lookupHandler";
/**
* Constructs a new bean post-processor for Zuul.
*
* @param routeLocator the route locator.
* @param zuulController the Zuul controller.
* @param errorController the error controller.
* @return the new bean post-processor.
*/
@Bean
public ZuulPostProcessor zuulPostProcessor(@Autowired RouteLocator routeLocator,
@Autowired ZuulController zuulController,
@Autowired(required = false) ErrorController errorController) {
return new ZuulPostProcessor(routeLocator, zuulController, errorController);
}
private enum LookupHandlerCallbackFilter implements CallbackFilter {
INSTANCE;
@Override
public int accept(Method method) {
if (METHOD.equals(method.getName())) {
return 0;
}
return 1;
}
}
private enum LookupHandlerMethodInterceptor implements MethodInterceptor {
INSTANCE;
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (ERROR_PATH.equals(args[0])) {
// by entering this branch we avoid the ZuulHandlerMapping.lookupHandler method to trigger the
// NoSuchMethodError
return null;
}
return methodProxy.invokeSuper(target, args);
}
}
private static final class ZuulPostProcessor implements BeanPostProcessor {
private final RouteLocator routeLocator;
private final ZuulController zuulController;
private final boolean hasErrorController;
ZuulPostProcessor(RouteLocator routeLocator, ZuulController zuulController, ErrorController errorController) {
this.routeLocator = routeLocator;
this.zuulController = zuulController;
this.hasErrorController = (errorController != null);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (hasErrorController && (bean instanceof ZuulHandlerMapping)) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ZuulHandlerMapping.class);
enhancer.setCallbackFilter(LookupHandlerCallbackFilter.INSTANCE); // only for lookupHandler
enhancer.setCallbacks(new Callback[] {LookupHandlerMethodInterceptor.INSTANCE, NoOp.INSTANCE});
Constructor<?> ctor = ZuulHandlerMapping.class.getConstructors()[0];
return enhancer.create(ctor.getParameterTypes(), new Object[] {routeLocator, zuulController});
}
return bean;
}
}
}
15、负责均衡找不到下游服务的问题
增加如下类:
代码语言:javascript复制public class RibbonEurekaClientConfig {
@Autowired
private DiscoveryClient discoveryClient;
@Bean
@Lazy
public IPing ribbonPing() {
return new DummyPing();
}
@Bean
@Lazy
public IRule ribbonRule(IClientConfig clientConfig) {
AvailabilityFilteringRule rule = new AvailabilityFilteringRule();
rule.initWithNiwsConfig(clientConfig);
return rule;
}
@Bean
@Lazy
public ServerList<?> ribbonServerList(IClientConfig clientConfig) {
return new ServerList<Server>() {
@Override
public List<Server> getInitialListOfServers() {
return new ArrayList<>();
}
@Override
public List<Server> getUpdatedListOfServers() {
List<Server> serverList = new ArrayList<>();
List<ServiceInstance> instances = discoveryClient.getInstances(clientConfig.getClientName());
if (instances != null && instances.size() == 0) {
return serverList;
}
for (ServiceInstance instance : instances) {
if (instance.isSecure()) {
serverList.add(new Server("https", instance.getHost(), instance.getPort()));
} else {
serverList.add(new Server("http", instance.getHost(), instance.getPort()));
}
}
return serverList;
}
};
}
}
在Spring Boot 启动类上配置
@RibbonClients(defaultConfiguration = RibbonEurekaClientConfig.class)
基于Spring Boot 3.1.0 系列文章
- Spring Boot 源码阅读初始化环境搭建
- Spring Boot 框架整体启动流程详解
- Spring Boot 系统初始化器详解
- Spring Boot 监听器详解
- Spring Boot banner详解
- Spring Boot 属性配置解析
- Spring Boot 属性加载原理解析
- Spring Boot 异常报告器解析
- Spring Boot 3.x 自动配置详解