一、使用场景/原因
-
过渡期迁移:
- 当系统从一个服务注册中心迁移到另一个时,例如从 Eureka 迁移到 Nacos,可以在过渡期内同时使用两个注册中心,确保服务平稳迁移,逐步过渡,避免一次性切换带来的风险。
-
兼容性考虑:
- 不同的微服务可能使用不同的注册中心,为了兼容这些微服务,可以同时支持 Nacos 和 Eureka。这样既可以支持新开发的服务使用 Nacos,也可以兼容旧有的使用 Eureka 的服务。
二、增加注册中心
本篇文章我们升级的项目本身现在使用的是Eureka,然后新创建的项目采用的是 Nacos来作为注册中心,这就会出现一个问题 , 那就是微服务之间调用困难, 因为新旧微服务分别都注册在不同的注册中心。如果采用一次性整体切换成Nacos,对于已经运行了很久的现有项目来说, 工作量有点大, 所以我们采用这种办法, 就是项目同时支持Nacos、Eureka两个服务注册,为后续的逐步迁移做准备。
2.1、Pom文件分别配置Nacos、Eureka
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.2、启动类注解
1、注释掉 @EnableEurekaClent // 弃用Eureka 专门的注册注解
2、新添加 @EnableDiscoveryClient
@SpringBootApplication
//@EnableEurekaClient
@EnableDiscoveryClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
2.3、项目配置文件Application.yml
eureka:client:serviceUrl:defaultZone: http://localhost:9002/eureka/instance:prefer-ip-address: true
server:port: 11500
spring:application:name: Kocloud:service-registry:auto-registration:enabled: falsenacos:discovery:server-addr: http://127.0.0.1:9999namespace: 47dea8bf-3dce-4c86-82bc-82f1497c57d2
三、启动项目
至此,并没有结束,配置结束后,我们来启动项目,看效果。
不出意外的话,会出现下面这个报错, 出意外的话那就是出意外了 🙃🙃🙃🙃
3.1、自动注册时候报错
图和文字是一样的 为了方便看,可方便复制
Disconnected from the target VM, address: 'localhost:63051', transport: 'socket'
***************************
APPLICATION FAILED TO START
***************************Description:Field autoServiceRegistration in org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration required a single bean, but 2 were found:- nacosAutoServiceRegistration: defined by method 'nacosAutoServiceRegistration' in class path resource [com/alibaba/cloud/nacos/registry/NacosServiceRegistryAutoConfiguration.class]- eurekaAutoServiceRegistration: defined by method 'eurekaAutoServiceRegistration' in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.class]Action:Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
言简意赅的阐述一下出现这个报错的原因是因为, @EnableDiscoveryClient 在启动的时候会进行自动注册, 干这件事情的就是 AutoServiceRegistrationAutoConfiguration ,然后这个了类在一开始 注入了一个类型为 AutoServiceRegistration的类
继续往下看, AutoServiceRegistration这个类的实现有两个,分别是EurekaAutoServiceRegistration 和 NacosAutoServiceRegistration,这都是因为引入了两个注册中心后导致的,
然后我们再说日志中给出的建议,他是说建议你在其中一个类上面加@Primary , 这样虽然能解决问题, 但是,这是源代码,无法修改的,难道不修改源码就没什么办法了么 ?
让我们在回到最开始的那个自动配置类上 , 注意看 , 这个类的init , 在进行了注入之后, 什么都没有做 , 就只是做了一下Check ,我个人感觉啊, 把这个自动配置类, 给忽略掉,也就是将其排除。 不让他自动执行!
3.2、注入失败问题解决
前面我们说到,为了解决在自动注册时候注入类时候出现两个配置类的问题, 我们采用排除这个配置类的方式,排除办法有两种, 可以根据习惯自行选择
3.2.1 application.yml 配置方式 autoconfigure.exclude
spring:application:name: Kocloud:nacos:discovery:server-addr: http://127.0.0.1:9999namespace: 47dea8bf-3dce-4c86-82bc-82f1497c57d2config:enabled: falseserver-addr: http://127.0.0.1:9999import-check: falsenamespace: 47dea8bf-3dce-4c86-82bc-82f1497c57d2autoconfigure:exclude: org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration
3.2.2 Application 启动类配置方式
// exclude 同样可以起到忽略的作用 ,至于这里为什么要忽略两个,继续往下看,会说到
@SpringBootApplication(exclude = {AutoServiceRegistrationAutoConfiguration.class,ServiceRegistryAutoConfiguration.class})
@EnableDiscoveryClient
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
然后我们再重启项目,提示的错误还有一个地方的注册配置类,遇到了同样的问题,(请注意,下面这个报错,如果你并没有使用 spring-boot-starter-actuator 这个组件就不会有这个问题)如下:
***************************
APPLICATION FAILED TO START
***************************Description:Field registration in org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration$ServiceRegistryEndpointConfiguration required a single bean, but 2 were found:- nacosRegistration: defined by method 'nacosRegistration' in class path resource [com/alibaba/cloud/nacos/registry/NacosServiceRegistryAutoConfiguration.class]- eurekaRegistration: defined in BeanDefinition defined in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration$RefreshableEurekaClientConfiguration.class]Action:Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed********
Disconnected from the target VM, address: 'localhost:63833', transport: 'socket'
这次提示的配置类是 ServiceRegistryAutoConfiguration , 按照老办法,直接忽略这个配置类, 但这个类不像上一个那样实际什么都没做,这个还是做了点事情的 , 这个类加载的目的是因为我们项目中使用到的 Spring的监控组件, 存在这个依赖时,即使执行了上文的操作,启动时还是报错。就是因为在启动之初这个监控组件会将Service注册,便于后续的监控,所以我们可以将这个也选择直接排除这个配置类, 至于影响嘛,无非就是监控组件中会少一个EndPoint,无伤大雅。
/*** @author Spencer Gibb*/
@Configuration(proxyBeanMethods = false)
public class ServiceRegistryAutoConfiguration {@ConditionalOnBean(ServiceRegistry.class)@ConditionalOnClass(Endpoint.class)protected class ServiceRegistryEndpointConfiguration {@Autowired(required = false)private Registration registration;@Bean@ConditionalOnEnabledEndpointpublic ServiceRegistryEndpoint serviceRegistryEndpoint(ServiceRegistry serviceRegistry) {ServiceRegistryEndpoint endpoint = new ServiceRegistryEndpoint(serviceRegistry);endpoint.setRegistration(this.registration);return endpoint;}}}
至此,分别排除了AutoServiceRegistrationAutoConfiguration 和 ServiceRegistryAutoConfiguration 这两个自动配置类后,项目便可以正常启动,且会注册到两个注册中心
但是请注意,这种行为并不是长久之道,只适合在项目架构升级过渡期使用,或者其他特殊场景下使用,日常使用中还是建议 使用同一种注册中心,