前言

前段时间,因项目被扫出大量漏洞,全是因为依赖版本过低,存在高中危漏洞需要升级。正好本来也有规划集群升级,因为工作量大迟迟落实不了,正好有这次修漏洞的机会,升级微服务集群。这篇文章主要记录了本人的升级记录,遇到的问题解决方法,仅供参考。

项目背景

项目微服务技术栈: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中加入依赖,过期的配置会提示:

<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以后不允许循环依赖

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、跨域头修改
由原来的修改为

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配置过期

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

修改:

  sql:
    init:
      platform: mysql
      #执行的sql语句
      data-locations: classpath:data.sql
      #执行的建表语句
      schema-locations: classpath:schema.sql

11、Eureka 配置的修改

instance-id: ${spring.cloud.client.ip-address}:${server.port}

metadata-map:
  user-name: ${spring.security.user.name}
  user-password: ${spring.security.user.password}

12、上传配置的修改

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

@Beanpublic LoadBalancerClient blockingLoadBalancerClient(LoadBalancerClientFactory loadBalancerClientFactory) {
   return new BlockingLoadBalancerClient(loadBalancerClientFactory);}

14、调用接口报NoSuchMethodError: org.springframework.boot.web.servlet.error.ErrorController.getErrorPath

增加如下类

@Configurationpublic 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、负责均衡找不到下游服务的问题
增加如下类:

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)

16、java.lang.NoSuchMethodError: com.netflix.servo.monitor.Monitors.isObjectRegistered(Ljava/lang/String;Ljava/lang/Object;)Z
zuul里的版本太久,需要排除

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
      <version>2.2.10.RELEASE</version>
      <!--zuul里的版本太久,要排除,否则报
      java.lang.NoSuchMethodError: com.netflix.servo.monitor.Monitors.isObjectRegistered(Ljava/lang/String;Ljava/lang/Object;)Z
      -->
      <exclusions>
        <exclusion>
          <groupId>com.netflix.servo</groupId>
          <artifactId>servo-core</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    转自:
    https://blog.csdn.net/weixin_40972073/article/details/134730145