因项目需要,一个springcloud微服务工程需要同时部署到A,B两个项目使用,但A项目使用Eureka注册中心,B项目使用Nacos注册中心,现在需要通过部署时修改配置来实现多注册中心的切换。
解决思路:如果同时引入nacos和eureka的依赖和配置,不做任何处理,会导致启动失败:
*************************** 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
不难看出失败原因是单例bean找到了两个实例,那么该如何解决这个问题呢?首先想到的肯定是删除掉暂时不需要使用的实例(如使用eureka注册中心则删掉引入pom的nacos依赖),这样做是没有问题的,但是维护成本比较高。能不能从springboot自动装配原理入手,找到更便捷的方法呢?接着看:
我们都知道SpringBoot的启动类的@SpringBootApplication是一个组合注解,它里面的@EnableAutoConfiguration会引入AutoConfigurationimportSelector.class
从这个类的方法getAutoConfigurationEntry()一层一层点进去看,
SpringFactoriesLoader.loadFactories()会去检索meta-INF/spring.factories文件。
protected List getAutoConfigurationimportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationimportFilter.class, this.beanClassLoader);
}
那么思路就比较清晰了,我们可以通过实现AutoConfigurationimportFilter接口,将自己的过滤逻辑写在实现类中,就可以实现自定义的自动装配过滤器了。
上代码:1.过滤器
package com.example.demo.business;
import com.example.demo.business.constants.RegistrationCenterConstants;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.AutoConfigurationimportFilter;
import org.springframework.boot.autoconfigure.AutoConfigurationmetadata;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
public class EngineAutoConfigurationimportFilter implements AutoConfigurationimportFilter, EnvironmentAware {
private Environment environment;
@Override
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationmetadata autoConfigurationmetadata) {
//获取配置的注册中心,默认为nacos
String registryType = environment.getProperty("registry.type", RegistrationCenterConstants.NACOS);
boolean[] match = new boolean[autoConfigurationClasses.length];
//当自定义标识为eureka,则排除nacos的自动装配,反之同理;
if (registryType.equals(RegistrationCenterConstants.EUREKA)) {
for (int i = 0; i < autoConfigurationClasses.length; i++) {
match[i] = !StringUtils.isNotBlank(autoConfigurationClasses[i]) ||
!autoConfigurationClasses[i].equals(RegistrationCenterConstants.NACOS_SERVICE_REGISTRY_AUTO_CONFIGURATION);
}
} else {
for (int i = 0; i < autoConfigurationClasses.length; i++) {
if (StringUtils.isNotBlank(autoConfigurationClasses[i])){
match[i] = !RegistrationCenterConstants.EUREKA_DISCOVERY_CLIENT_CONFIGURATION.equals(autoConfigurationClasses[i])
&& !RegistrationCenterConstants.EUREKA_AUTO_CONFIGURATION_CLASSES.equals(autoConfigurationClasses[i]);
}
}
}
return match;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
2.常量类
package com.example.demo.business.constants;
public class RegistrationCenterConstants {
public static final String NACOS = "nacos";
public static final String EUREKA = "eureka";
public static final String EUREKA_AUTO_CONFIGURATION_CLASSES = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration";
public static final String EUREKA_DISCOVERY_CLIENT_ConFIGURATION = "org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration";
public static final String NACOS_SERVICE_REGISTRY_AUTO_ConFIGURATION = "com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration";
}
3.spring.factories文件(注意路径一定要在meta-INF包下)
org.springframework.boot.autoconfigure.AutoConfigurationimportFilter= com.example.demo.business.EngineAutoConfigurationimportFilter
4.配置文件添加
registry: type: nacos效果
通过修改配置项registry.type就可以实现eureka和nacos的切换了
eureka:
nacos:



