一、使用场景/原因
-
过渡期迁移:
- 当系统从一个服务注册中心迁移到另一个时,例如从 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: Ko
cloud:
service-registry:
auto-registration:
enabled: false
nacos:
discovery:
server-addr: http://127.0.0.1:9999
namespace: 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: Ko
cloud:
nacos:
discovery:
server-addr: http://127.0.0.1:9999
namespace: 47dea8bf-3dce-4c86-82bc-82f1497c57d2
config:
enabled: false
server-addr: http://127.0.0.1:9999
import-check: false
namespace: 47dea8bf-3dce-4c86-82bc-82f1497c57d2
autoconfigure:
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
@ConditionalOnEnabledEndpoint
public ServiceRegistryEndpoint serviceRegistryEndpoint(
ServiceRegistry serviceRegistry) {
ServiceRegistryEndpoint endpoint = new ServiceRegistryEndpoint(
serviceRegistry);
endpoint.setRegistration(this.registration);
return endpoint;
}
}
}
至此,分别排除了AutoServiceRegistrationAutoConfiguration 和 ServiceRegistryAutoConfiguration 这两个自动配置类后,项目便可以正常启动,且会注册到两个注册中心
但是请注意,这种行为并不是长久之道,只适合在项目架构升级过渡期使用,或者其他特殊场景下使用,日常使用中还是建议 使用同一种注册中心,