Spring Cloud 发现多个服务版本

标签 spring spring-cloud netflix-eureka spring-cloud-feign

我在问自己一个问题,但没有找到答案。也许这里有人对此有想法;-) 在 Spring Cloud 中使用服务注册表 (Eureka) 以及 RestTemplate 和 Feign 客户端,我拥有同一服务的不同构建版本。通过 Actuator 的/info 端点记录构建版本。

{
"build": {
"version": "0.0.1-SNAPSHOT",
"artifact": "service-a",
"name": "service-a",
"group": "com.mycompany",
"time": 1487253409000
}
}
...
{
"build": {
"version": "0.0.2-SNAPSHOT",
"artifact": "service-a",
"name": "service-a",
"group": "com.mycompany",
"time": 1487325340000
}
}

有什么办法可以在客户调用时询问特定的构建版本吗? 我应该使用网关的路由过滤器来管理它吗?但我想版本检测仍然是一个问题......

好吧,任何建议表示赞赏。

最佳答案

好的。这是将构建版本注入(inject)到要由 Eureka 注册的服务(“service-a”)实例元数据中的代码:

@Configuration
@ConditionalOnClass({ EurekaInstanceConfigBean.class, EurekaClient.class })
public class EurekaClientInstanceBuildVersionAutoConfiguration {

    @Autowired(required = false)
    private EurekaInstanceConfig instanceConfig;

    @Autowired(required = false)
    private BuildProperties buildProperties;

    @Value("${eureka.instance.metadata.keys.version:instanceBuildVersion}")
    private String versionMetadataKey;

    @PostConstruct
    public void init() {
        if (this.instanceConfig == null || buildProperties == null) {
            return;
        }
        this.instanceConfig.getMetadataMap().put(versionMetadataKey, buildProperties.getVersion());
    }
}

这是验证“service-b”内元数据传输的代码:

@Component
public class DiscoveryClientRunner implements CommandLineRunner {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private DiscoveryClient client;

    @Override
    public void run(String... args) throws Exception {
        client.getInstances("service-a").forEach((ServiceInstance s) -> {
            logger.debug(String.format("%s: %s", s.getServiceId(), s.getUri()));
            for (Entry<String, String> md : s.getMetadata().entrySet()) {
                logger.debug(String.format("%s: %s", md.getKey(), md.getValue()));
            }
        });
    }
}

请注意,如果“虚线组合”(即“instance-build-version”),则元数据键强制采用驼峰式大小写。

这是我发现的根据版本过滤服务实例的解决方案:

@Configuration
@EnableConfigurationProperties(InstanceBuildVersionProperties.class)
public class EurekaInstanceBuildVersionFilterAutoConfig {

    @Value("${eureka.instance.metadata.keys.version:instanceBuildVersion}")
    private String versionMetadataKey;

    @Bean
    @ConditionalOnProperty(name = "eureka.client.filter.enabled", havingValue = "true")
    public EurekaInstanceBuildVersionFilter eurekaInstanceBuildVersionFilter(InstanceBuildVersionProperties filters) {
        return new EurekaInstanceBuildVersionFilter(versionMetadataKey, filters);
    }
}

@Aspect
@RequiredArgsConstructor
public class EurekaInstanceBuildVersionFilter {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final String versionMetadataKey;
    private final InstanceBuildVersionProperties filters;

    @SuppressWarnings("unchecked")
    @Around("execution(public * org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient.getInstances(..))")
    public Object filterInstances(ProceedingJoinPoint jp) throws Throwable {
        if (filters == null || !filters.isEnabled()) logger.error("Should not be filtering...");
        List<ServiceInstance> instances = (List<ServiceInstance>) jp.proceed();
        return instances.stream()
                .filter(i -> filters.isKept((String) jp.getArgs()[0], i.getMetadata().get(versionMetadataKey))) //DEBUG MD key is Camel Cased!
                .collect(Collectors.toList());
    }
}

@ConfigurationProperties("eureka.client.filter")
public class InstanceBuildVersionProperties {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * Indicates whether or not service instances versions should be filtered
     */
    @Getter @Setter
    private boolean enabled = false;

    /**
     * Map of service instance version filters.
     * The key is the service name and the value configures a filter set for services instances
     */
    @Getter
    private Map<String, InstanceBuildVersionFilter> services = new HashMap<>();

    public boolean isKept(String serviceId, String instanceVersion) {
        logger.debug("Considering service {} instance version {}", serviceId, instanceVersion);
        if (services.containsKey(serviceId) && StringUtils.hasText(instanceVersion)) {
            InstanceBuildVersionFilter filter = services.get(serviceId);
            String[] filteredVersions = filter.getVersions().split("\\s*,\\s*");    // trimming
            logger.debug((filter.isExcludeVersions() ? "Excluding" : "Including") + " instances: " + Arrays.toString(filteredVersions));
            return contains(filteredVersions, instanceVersion) ? !filter.isExcludeVersions() : filter.isExcludeVersions();
        }
        return true;
    }

    @Getter @Setter
    public static class InstanceBuildVersionFilter {
        /**
         * Comma separated list of service version labels to filter
         */
        private String versions;
        /**
         * Indicates whether or not to keep the associated instance versions.
         * When false, versions are kept, otherwise they will be filtered out
         */
        private boolean excludeVersions = false;
    }
}

您可以为每个使用的服务指定预期或避免版本的列表,并且将相应地过滤发现。

logging.level.com.mycompany.demo=DEBUG

eureka.client.filter.enabled=true

eureka.client.filter.services.service-a.versions=0.0.1-SNAPSHOT

请将任何建议作为评论提交。谢谢

关于Spring Cloud 发现多个服务版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42296407/

相关文章:

java - Spring框架关系映射

Spring Boot Jpa JPQL 选择特定列以外的列

docker - 在当前项目和插件组中找不到前缀 'docker' 的插件

kubernetes - 在 Kubernetes 下调度任务失败

java - Spring Boot微服务已注册到Eureka但无法命中

java - spring-boot-admin,版本和信息未显示

java - Spring JPA : XML Configuration - No qualifying bean of Repository/no declaration can be found for element 'jpa:repositories'

java - hibernate/Java : retrieving primary key always returns zero

spring - 由 : java. lang.IllegalStateException 引起:您需要为 git 存储库配置 uri

spring-boot - 在 Kubernetes 上使用 Netflix Eureka